I have the following block of Ruby code within a class:
def self.blacklisted_keywords
%w(acquista acquistiamo acquisto acquistano compro compriamo comprano)
end
private
def item_valid?
keywords = blacklisted_keywords
end
Why can't I call blacklisted_keywords without getting: "undefined method `blacklisted_keywords'"? What am I doing wrong?
Because blacklisted_keywords is not an instance method, rather a class method.keywords = blacklisted_keywords means ruby looking at it implicitly as keywords = self.blacklisted_keywords. That causes an error, as it is not an instance method. Replace keywords = blacklisted_keywords as keywords = self.class.blacklisted_keywords
Following the answers provided, maybe it would make sense to keep the keywords in a constant if you don't need to mutate them.
class Blah
BLACKLISTED_KEYWORDS = %w(acquista acquistiamo acquisto acquistano compro compriamo comprano)
private
def item_valid?
keywords = BLACKLISTED_KEYWORDS
end
end
Related
Let's consider following code:
class Try
CONST = xxx("42")
private_class_method def self.xxx(str)
str.to_i
end
end
puts Try::CONST
It produces an error: undefined method `xxx' for Try:Class (NoMethodError)
It seems that I cannot use a class private method to initialise a constant. The example is doing nothig actually, but it is a reproduction of an error I am facing trying to read data from file into the class constant.
Is it becuse ruby tries to initialize a constant before it get know about all methodes, or am I doing something wrong?
Not really. What you can't do is to assign the value of something that still hasn't been defined to something else in order to hold its value.
It has nothing to do with the method visibility because this works:
class Try
private_class_method def self.xxx(str)
str.to_i
end
CONST = xxx("42")
end
p Try::CONST
# 42
I have searched around for the answer to this and I can see a lot of similar problems but I still do not understand what I am doing wrong here. I have declared a Ruby class and attempted to new it and then call some instance methods on the instance, so why do I get the NoMethodError on my start method?
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def self.start(port)
...
end
end
test = MyClass.new
test.start '8082' <- here <- undefined method `start' for #<MyClass:0x2f494b0> (NoMethodError)
As you can see I am a Ruby noob. Any help would be appreciated. I can change my class structure but I would really like to understand what I am doing wrong here.
here start is a class method.
By your current approach, you can use it in the following way
MyClass.start '8080'
But if you want to use it on instance of class then use the following code
class MyClass
def initialize
self.class.reset
end
def self.reset
...
end
def start(port)
...
end
end
test = MyClass.new
test.start '8080'
You are using start as a Class variable, the method names preceded with self-keyword make those methods as Class methods. So if you really want to not change your class then you should call it like this:
MyClass.start '8080'
Else you can remove the self from your reset and start methods and make them as Instance methods and use them as:
test = MyClass.new
test.start '8082'
I am wondering if there is an easy way to pass all local variables when calling a method, instead of passing them one by one as parameters. I want the following:
class Greeting
def hello
message = 'HELLO THERE!'
language = 'English'
say_greeting
end
def konnichiwa
message = 'KONNICHIWA!'
language = 'Japanese'
say_greeting
end
private def say_greeting
puts message
end
end
Greeting.new.hello
to show HELLO THERE!. But it returns an error: NameError: undefined local variable or method 'message'.
I tried local_variables to get all local variables as an Array of symbols. But I can't seem to access the actual variables because there seemed to be no Ruby method like local_variable_get.
Background of the problem
In my Rails application, I have a controller having three update methods for different view files. All of them behave exactly the same (that they all will update a resource, show error if any, etc). Their only main difference are
template to be rendered when unsuccessful
redirect url when successful
flash success message
I only have three variables, so it really is indeed easy to just pass them as parameters, but I am just wondering if there is an elegant solution to this.
Local variables are there to do precisely not what you are trying to do: encapsulate reference within a method definition. And instance variables are there to do precisely what you are trying to: sharing information between different method calls on a single object. Your use of local variable goes against that.
Use instance variables, not local variables.
If you insist on referencing local variables between methods, then here is a way:
class Greeting
def hello
message = 'HELLO THERE!'
language = 'English'
say_greeting(binding)
end
def konnichiwa
message = 'KONNICHIWA!'
language = 'Japanese'
say_greeting(binding)
end
private def say_greeting b
puts b.local_variable_get(:message)
end
end
You can't make it without passing any arguments, but you can just pass a single binding argument, and refer all local variables from there.
Make the message and language as instance variables.
Then you can access them inside the private method.
class Greeting
def hello
#message = 'HELLO THERE!'
#language = 'English'
say_greeting
end
def konnichiwa
#message = 'KONNICHIWA!'
#language = 'Japanese'
say_greeting
end
private
def say_greeting
puts #message
end
end
puts Greeting.new.hello
Use instance variables. In your method say_greeting make sure you call the method hello first, otherwise the value of #message will be nil.
def hello
#message = "Hello there"
end
def say_greeting
hello #method call
puts message
end
I am executing a class with only this code in rubymine:
def saythis(x)
puts x
end
saythis('words')
It returns an error: undefined method `saythis', rather than printing the string 'words'. What am I missing here? Replicating this code in irb prints the string 'words'.
I assume you wrote a class like the one below and did not write that code into a irb console. The problem is that you define an instance method, but try to call the method from the class level.
class Foo
def say_this(x) # <= defines an instance method
puts x
end
say_this('words') # <= calls a class method
end
There a two ways to "fix" this:
Define a class method instead of an instance method: def self.say_this(x)
Call the instance method instead of the class method call: new.say_this(x)
I have an array of three NetAddr::CIDR objects and am attempting to sort them using the cidr_sort method of the NetAddr module (http://rubydoc.info/gems/netaddr/1.5.0/NetAddr#cidr_sort-class_method)
When I call the sort method from within my Class as follows:
Class IPv4SummaryNet
attr_accessor :component_nets
#component_nets = []
def add_net(net)
#component_nets = component_nets.to_a.push(net)
end
def sort_component_nets
component_nets_sorted = #component_nets.sort
end
...
end
I get the following error: /usr/local/lib/ruby/gems/2.1.0/gems/netaddr-1.5.0/lib/cidr_shortcuts.rb:216:in 'cidr_sort': undefined method 'length' for #<NetAddr::CIDRv4:0x007f55cbae0088> (NoMethodError)
But if I print the array length from within my program, I get the correct value of 3.
I have also tried using sort_by and NetAddr::cidr_sort(#component_nets) and get the same error.
Why is Ruby telling me length is undefined when the cidr_sort method tries to call it, yet I can call it in my code with no problem?
def sort_component_nets
component_nets_sorted = #component_nets.sort
end
Here Ruby thinks you are trying to create a local variable within the method block, but I assume that you actually want to access the method component_nets_sorted that is outside the block. To do this: you must add the self. prefix to it.
def sort_component_nets
self.component_nets_sorted = #component_nets.sort
end