Ruby undefined method `pair_push' for nil:NilClass (NoMethodError) - ruby

I'm new to ruby
I created my own map class
class MyMap
attr_accessor :key,:value
def initialize
self.key = []
self.value = []
end
def pair_push(k, v)
self.key.push(k)
self.value.push(v)
end
...
end
And my own json object
class Json
attr_accessor :index,:data
def initialize
index=MyMap.new
data=MyMap.new
end
def create_index(_index, type, id)
index.pair_push("_index", _index)
index.pair_push("_type", type)
index.pair_push("_id", id)
end
def add_to_data(attName, value)
data.pair_push attName, value
end
...
end
But when I try to use add_to_data
jsonDst.add_to_data(attributeName, arr[i]) I get the following error message
helloWorld.rb:66:in `add_to_data': undefined method `pair_push' for nil:NilClass (NoMethodError)
Note, before I invoke add_to_data I verify that attributeName != nil && arr[i] != nil

In the constructor you should use #instance_variables. In your Json class' constructor, when you refer to data, that's just an uninstantiated local variable. You should use #data instead. Same goes for #index:
class Json
attr_accessor :index,:data
def initialize
#index=MyMap.new
#data=MyMap.new
end
def create_index(_index, type, id)
index.pair_push("_index", _index)
index.pair_push("_type", type)
index.pair_push("_id", id)
end
def add_to_data(attName, value)
data.pair_push attName, value
end
...
end
Here's how it works: http://ideone.com/mpLroq

Related

Accessing instance variables from outside the class

I'm having issues understanding this encapsulation. I have instance variables defined with attr_accessor. I'm trying to access them outside class. But they are always nil and returns undefined method.
NoMethodError: undefined method `has_key?' for nil:NilClass
Please help me understand.
class TrieNode
attr_reader :value, :next, :children
def initalize
#value = nil
#children = Hash.new
#next = nil
end
end
class Trie
attr_accessor :root
def initialize
#root = TrieNode.new
end
def build_trie(strs)
cur = #root
strs.each do |str|
str.chars.each do |char|
if cur.children.has_key? char
cur = cur.children[char]
next
else
new_node = TrieNode.new
cur.children[char] = new_node
cur = new_node
end
end
cur = #root
end
end
end
Yes, it is not encapsulation, it is because your object is not instantiated properly, which is caused by a typo
def initalize
#value = nil
#children = Hash.new
#next = nil
end
should be initialize not initalize

ruby class undefined method (NoMethodError)

Unfortunately, I get the following error. I can't quite understand why it doesn't work?
:14:in `convert': undefined method `factors' for 30:Fixnum (NoMethodError)
from question_stack.rb:18:in `<main>'
I try to create the following class:
# Class Wordgame
class Wordgame
WORDGAME_MAP = {
'3' => 'baa',
'5' => 'bar',
'7' => 'bla'
}.freeze
def self.factors
(1..self).select { |n| (self % n).zero? }
end
def self.convert(number)
number.factors.map(&:to_s).each.map { |char| WORDGAME_MAP[char] }.join
end
end
Wordgame.convert(30)
What am I doing wrong? Where is my mental error?
self refers to the class itself in a class method or to the current object in an instance method. In your case it refers to WordGame, the object's class.
If you really want it to refer to 30 into the factors method you have to define it as an instance method, because called on an object (30), not a class (Integer), opening the Integer class
class Integer
def factors
(1..self).select { |n| (self % n).zero? }
end
end
I think you know the alternative:
def self.factors(x)
(1..x).select { |n| (self % n).zero? }
end
def self.convert(number)
factors(number).map(&:to_s).each.map { |char| WORDGAME_MAP[char] }.join
end
Or better, with OOP.
class WordGame
def initialize(n)
#n = n
end
def convert
factors.map(&:to_s).each.map { |char| WORDGAME_MAP[char] }.join
end
private
def factors
(1..#n).select { |m| (#n % m).zero? }
end
end
Wordgame.new(30).convert

How do I access class methods in a define_singleton_method block in Ruby

I am trying to access class methods within a define_singleton_method block, but it doesn't seem to be working.
Here is an example.
class Test
attr_accessor :tags
def initialize
#tags = []
#tags.define_singleton_method(:<<) do |val|
val = tosymbol(val)
push(val)
end
end
def tosymbol(value)
value = value.to_s
value = value.gsub!(/\s+/,'_') || value
value = value.downcase! || value
return value.to_sym
end
end
But when I use it I get an error.
test = Test.new
test.tags<<"Hello World"
NoMethodError: undefined method `tosymbol' for []:Array
from /home/joebloggs/GitHub/repo/file.rb:183:in `block in initialize'
from (irb):9
from /home/joebloggs/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
I tried changing val = tosymbol(val) to val = Test::tosymbol(val) but that didn't work either, I get undefined method 'tosymbol' for Test:Class
I could re-write what tosymbol is doing, but it wouldn't be very DRY. Where am I going wrong? Thanks.
Where am I going wrong?
You're (re)defining a << method for instance of Array class, not Test class.
While doing so you are trying to access tosymbol method, that is not defined in Array class, but in Test class.
What you want, probably (read judging by your code sample), is to define << method for instances of Test class:
def initialize
#tags = []
end
def <<(val)
tags << tosymbol(val)
end
test = Test.new
test << "Hello World"
#=> [:hello_world]
EDIT
To make your example to work you just need to assign the instance to a variable and call the tosymbol method with correct receiver:
def initialize
#tags = []
test = self # <============
#tags.define_singleton_method(:<<) do |val|
val = test.tosymbol(val)
push(val)
end
end
Now:
test.tags << 'Hello World'
#=> [:hello_world]

Add hash argument or string argument in a method to a hash (Ruby)

If the argument "entry" to the method add is a hash I need to add it to the :entries hash. If "entry" is a string "entry" needs to be set as a key in the hash and its value to nil. I have a solution below but is there a cleaner way to do this?
class Test
attr_accessor :entries
def initialize
#entries = {}
end
def add(entry)
if entry.is_a?(Hash)
entry.each do |word, definition|
#entries[word] = definition
end
else
#entries[entry] = nil
end
end
end
#test = Test.new
#test.add("the")
#{"the" => nil}
#test.add("the" => "one")
#{"the"=>"one"}
I refactored the code:
class Test
attr_accessor :entries
def initialize
#entries = {}
end
def add(entry)
entry.is_a?(Hash) ? #entries.merge!(entry) : #entries[entry] = nil
end
end

Why can't I use a class instance variable inside a singleton class definition?

I'm trying to set an instance variable inside a singleton class and I can't get it to work.
Here's a simplified version of the problem:
class MyClass
class << self
attr :my_attr
#my_attr = {}
def my_method (x, y)
(#my_attr[x] ||= []) << y
end
end
end
MyClass.my_method(1, 2)
# => NoMethodError: undefined method `[]' for nil:NilClass
Here's the original code sample:
class Mic
class Req < Rack::Request; end
class Res < Rack::Response; end
class << self
attr :routes
#routes = {}
def call(env)
dup.call!(env)
end
def call!(env)
(#app||=new).call(env)
end
def get(path, opts={}, &blk)
puts #routes.inspect # nil
route 'GET', path, opts, &blk
end
def route(type, path, opts, &blk)
(#routes[type]||=[]) << {type: type, path: path, opts: opts, blk: blk}
end
end
def call(env)
#env = env
#req = Req.new(env)
#res = Res.new
#res.finish
end
end
So, abbreviated code, but what you probably want is to avoid accessing the instance variable as much as possible.
class Mic
class << self
def routes
#routes ||= {}
end
def method_which_acccess_routes
routes[:this] = :that
end
end
def instance_method_access_routes
Mic.routes[:the_other] = :nope
end
end
You can modify routes in place this way without an accessor, but if you need to completely overwrite it, you'll need an attr_writer method for routes as well.

Resources