I have this very simple piece of code (using Ruby 3)
def eat(main, dessert*)
if dessert.empty?
puts "I eat #{main}"
else
puts "I eat #{main} than #{dessert}."
end
end
Wher I run eat("mushrooms") that provokes errors:
argu.rb:1: syntax error, unexpected '*', expecting ')'
def manger(plat, dessert*)
argu.rb:7: syntax error, unexpected `end', expecting end-of-input
I don't see why.
Splat operator should put before parameters so your signature should be
def eat(main, *dessert)
Not sure where you got the idea from using dessert*, but you could define your method as
def eat(main, dessert = [])
to provide a default argument (of course it must be one which can respond to empty?).
Of course it is up to you to justify, why "main" can be anything (i.e. a String), but dessert must be a collection. I would test for dessert as
if dessert.nil?
and hence provide nil as default value for the dessert.
Related
Consider the following two code examples:
1
# Implicit Return
def yo
'swag', 'yolo'
end
whaat, ya = yo
puts ya
puts whaat
2
# Explicit Return
def yo
return 'swag', 'yolo'
end
whaat, ya = yo
puts ya
puts whaat
The first example returns this error: syntax error, unexpected ',', expecting keyword_end and the 2nd example works like a champ.
So, this got me curious as I know there a lot of shortcuts(idioms) in Ruby ( e.g. 2 + 2 is actually 2.+(2) ) and if something is not working right always be clearer in your syntax and take the idioms out.
Thus, my question is how does Ruby handle returns behind the scenes as to me this shouldn't throw an error?
Methods (and blocks, and class definitions, and module definitions) implicitly return the last expression evaluated. a, b is simply not a valid expression, it isn't even valid syntactically. return a, b is a valid expression: you are passing two arguments to the return keyword. Passing more than one argument, and leaving out the parenthesis is perfectly legal.
For a similar reason, foo(a, b) works, but foo (a, b) doesn't: the former is passing two arguments to foo, the latter is passing one argument (a, b) to foo, which is syntactically invalid.
I think it might be
def yo
['swag', 'yolo']
end
It should work but it doesn't answer to your question
I'm trying to complete an exercism.io test file which compares two strings and adds one to a counter each time there is a difference between the two strings. I've written my class, but for some reason it won't run in terminal. I've compared my code with several examples of syntax online and don't see why it won't run. Any help would be much appreciated.
Here's my class:
class Hamming
def compute(str1, str2)
distance = 0
length = str1.length
for i in 0..length
if str1[i] != str2[i] then
distance++
end
end
return distance
end
end
And here's a relevant bit of test file:
class HammingTest < Minitest::Test
def test_identical_strands
assert_equal 0, Hamming.compute('A', 'A')
end
end
Lastly, here's the error I'm getting:
hamming_test.rb:4:in `require_relative': /Users/Jack/exercism/ruby/hamming/hamming.rb:8: syntax error, unexpected keyword_end (SyntaxError)
/Users/Jack/exercism/ruby/hamming/hamming.rb:12: syntax error, unexpected end-of-input, expecting keyword_end
from hamming_test.rb:4:in `<main>'
You don't need then after condition in if statement.
Use two spaces instead of four for indentation in Ruby.
(Direct cause of your error) there's no ++ operator in Ruby. You should have
distance += 1
Ruby doesn't like this:
item (:name, :text) {
label('Name')
}
And I don't know why. I'm attempting to create a DSL. The 'item' method looks like this:
def item(name, type, &block)
i = QbeItemBuilder.new(#ds, name, QbeType.gettype(type))
i.instance_exec &block
end
Take a name for the item, a type for the item, and a block. Construct an item builder, and execute the block in its context.
Regardless of whether or not I need to use instance_exec (I'm thinking that I don't - it can be stuffed in the initialiser), I get this:
SyntaxError (ds_name.ds:5: syntax error, unexpected ',', expecting ')'
item (:name, :text) {
^
How do I invoke method with multiple arguments and a block? What does ruby think I'm trying to do?
The space before parentheses is causing ruby to evaluate (:name, :text) as single argument before calling the method which results in a syntax error. Look at these examples for illustration:
puts 1 # equivalent to puts(1) - valid
puts (1) # equivalent to puts((1)) - valid
puts (1..2) # equivalent to puts((1..2)) - valid
puts (1, 2) # equivalent to puts((1, 2)) - syntax error
puts(1, 2) # valid
Your way of providing the block is syntactically valid, however when the block is not in the same line as the method call it is usually better to use do ... end syntax.
So to answer your question you can use:
item(:name, :text) { label('Name') }
or:
item(:name, :text) do
label('Name')
end
Remove the space before the ( in item (:name, :text) {
Say I have class Player and I want a boolean method to check if a player is attacked:
class Player
attr_accessor :name, :health, :attacked?
def initialize(name)
#name = name
#health = 100
#attacked? = false
end
end
I get a syntax error:
SyntaxError: (irb):14: syntax error, unexpected '='
#attacked? = false
^
from /usr/bin/irb:12:in `<main>'
Removing the question mark from attacked fixes the problem, but I thought it would better follow convention to have attacked? in my code. It's not a big deal to forgo the question mark, but why are zero? and nil? conventions when#variables? and def methods?= are invalid?
Note that if you comment out the line causing your error (#attacked? = false), you will still get an error relating to the question mark:
NameError: invalid attribute name `attacked?'
The problem is that ? is not a valid character in a variable name. The first error (the SyntaxError that you’re seeing) is caused at parse time and caught immediately. The second error is caused when Ruby tries to evaluate the code and cannot create an instance variable with a name containing an invalid character.
A question mark is a valid character at the end of a method name though (actually it’s possible to have a method with a ? anywhere in its name, but you can’t call such a method directly).
One way to achieve what you want is something like this:
class Player
attr_accessor :name, :health, :attacked
alias :attacked? :attacked
def initialize(name)
#name = name
#health = 100
#attacked = false
end
end
This leaves attacked without the question mark, but adds attacked? as an alias.
I've run into the same problem before, and wished that I could make instance variables with a trailing question mark. It seems to be a corner case in Ruby's grammar. Check this out:
>> 1 ? 2 : 3
=> 2
>> 1?2:3
=> 2
>> #a = true
=> true
>> #a?1:2
=> 1
>> a = true
=> true
>> a ? 1 : 2
=> 1
>> a?1:2
SyntaxError: (irb):9: syntax error, unexpected ':', expecting $end
So the ? symbol is overloaded in Ruby's grammar -- it is used for the ternary operator, and as part of valid identifiers for method names. This causes ambiguity in the last case, where Ruby's lexer seems to bite off the a? as a single token, which leaves it unable to parse the rest of the ternary operator properly. With instance variables, this can't happen.
Again, I agree that allowing question marks in instance variable names would be very useful, certainly more valuable than making some obscure uses of the ternary operator non-ambiguous.
In Settingslogic fork allowing array as source, in ruby 1.8.7 everything is working, but in ruby 1.9.2 there is an error. The problem is within this part of the code:
self.class.class_eval <<-EndEval
def #{key}
return ##{key} if ##{key}
raise MissingSetting, "Missing setting '#{key}' in #{#section}" unless has_key? '#{key}'
value = fetch('#{key}')
##{key} = value.is_a?(Hash) ? self.class.new(value, "'#{key}' section in #{#section}") : value
end
EndEval
#section == ["path_to_yml_file1", "path_to_yml_file2",...]
Looks like #{} is evaluated in some strange way, "#{#section}" seems to be an array, not a string. Can anybody explain this?
Error trace:
#section == ["User/project/config/defaults.yml", "/Users/project/config/development.yml"]
ruby-1.9.2-p290 :001 > Settings.keys
SyntaxError: (eval):3: syntax error, unexpected tSTRING_BEG, expecting keyword_end
...project/config/defaults.yml", "/Users/project...
... ^
(eval):3: syntax error, unexpected tSTRING_BEG, expecting keyword_end
...project/config/development.yml"]" unless has_key? 'front'
... ^
(eval):5: syntax error, unexpected tSTRING_BEG, expecting ')'
...project/config/defaults.yml", "/Users/project...
... ^
(eval):5: syntax error, unexpected tSTRING_BEG, expecting keyword_end
...project/config/development.yml"]") : value
... ^
(eval):5: syntax error, unexpected ')', expecting keyword_end
...project/config/development.yml"]") : value
... ^
from .../settingslogic-3b5d7d9cc319/lib/settingslogic.rb:198:in `class_eval'
Thanks for any help
You've made a fork from main settingslogic. At that time it didn't support array as source, but now it does. Try to use main settingslogic repository.
Your error now related to this string:
raise MissingSetting,
"Missing setting '#{key}' in #{#section}" unless has_key? '#{key}'
because in case of using array instead of string
./settings.yml
you get something like this:
[\"./settings.yml\"]
The same happens with ##{key} assignment below. In main repository this code replaced to string concatenation.
Try self.class_eval or even without self, no need to get the name of class and self automatically assign to current object i.e. your class.