Ruby Mixin Undefined Method - ruby

So, I know there is a simple error, but I just can't seem to spot it. I'm using Modules/Mixins for the first time and any help would be much appreciated. I keep getting this error:
undefined method `this_is' for Value:Module (NoMethodError)
But it looks like the method is there...Here are is my module and classes...
module Value
def this_is
puts "#{self.players_hand} is the players hand"
end
end
require './value.rb'
class Player
include Value
attr_accessor :players_hand
def initialize
#players_hand = 0
end
def value_is
Value.this_is
end
end
require './player.rb'
class Game
def initialize
#player = Player.new
end
def start
puts #player.players_hand
puts #player.value_is
end
end
game = Game.new
game.start

When you include Value inside of the Player class, you are making the Value module's methods a part of the Player class, so the this_is method is not namespaced. Knowing that, we need to change this method:
def value_is
Value.this_is
end
To:
def value_is
this_is
end

Related

How could I implement something like Rails' before_initialize/before_new in plain Ruby?

In Rails we can define a class like:
class Test < ActiveRecord::Base
before_initialize :method
end
and when calling Test.new, method() will be called on the instance. I'm trying to learn more about Ruby and class methods like this, but I'm having trouble trying to implement this in plain Ruby.
Here's what I have so far:
class LameAR
def self.before_initialize(*args, &block)
# somehow store the symbols or block to be called on init
end
def new(*args)
## Call methods/blocks here
super(*args)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end
I'm trying to figure out where to store the blocks in self.before_initialize. I originally tried an instance variable like #before_init_methods, but that instance variable wouldn't exist in memory at that point, so I couldn't store or retrieve from it. I'm not sure how/where could I store these blocks/procs/symbols during the class definition, to later be called inside of new.
How could I implement this? (Either having before_initialize take a block/proc/list of symbols, I don't mind at this point, just trying to understand the concept)
For a comprehensive description, you can always check the Rails source; it is itself implemented in 'plain Ruby', after all. (But it handles lots of edge cases, so it's not great for getting a quick overview.)
The quick version is:
module MyCallbacks
def self.included(klass)
klass.extend(ClassMethods) # we don't have ActiveSupport::Concern either
end
module ClassMethods
def initialize_callbacks
#callbacks ||= []
end
def before_initialize(&block)
initialize_callbacks << block
end
end
def initialize(*)
self.class.initialize_callbacks.each do |callback|
instance_eval(&callback)
end
super
end
end
class Tester
include MyCallbacks
before_initialize { puts "hello world" }
end
Tester.new
Left to the reader:
arguments
calling methods by name
inheritance
callbacks aborting a call and supplying the return value
"around" callbacks that wrap the original invocation
conditional callbacks (:if / :unless)
subclasses selectively overriding/skipping callbacks
inserting new callbacks elsewhere in the sequence
... but eliding all of those is what [hopefully] makes this implementation more approachable.
One way would be by overriding Class#new:
class LameAR
def self.before_initialize(*symbols_or_callables, &block)
#before_init_methods ||= []
#before_init_methods.concat(symbols_or_callables)
#before_init_methods << block if block
nil
end
def self.new(*args, &block)
obj = allocate
#before_init_methods.each do |symbol_or_callable|
if symbol_or_callable.is_a?(Symbol)
obj.public_send(symbol_or_callable)
else
symbol_or_callable.(obj)
end
end
obj.__send__(:initialize, *args, &block)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end

How to define an original name scope in module/class with Ruby

How to define an original name scope in module/class with Ruby
I want to implement class like the following:
module SomeModule
extend OriginalNameScope
scope(:some) do
def method1
puts 1
end
def method2
puts 2
end
end
end
class SomeClass
include SomeModule
end
c = SomeClass.new
# I want to call methods like the following:
c.some_method1
c.some_method2
How to implement the OriginalNameScope module? I found out to get the method definitions in this method, but I don't know how to redefine methods with a prefix scope.
module OriginalNameScope
def scope(name, &method_definition)
puts method_definition.class
# => Proc
end
end
This is actually just a combination of some simple standard Ruby metaprogramming patterns and idioms:
module OriginalNameScope
def scope(name)
singleton_class.prepend(Module.new do
define_method(:method_added) do |meth|
if name && !#__recursion_guard__
#__recursion_guard__ = meth
method = instance_method(meth)
undef_method(meth)
define_method(:"#{name}_#{meth}") do |*args, &block|
method.bind(self).(*args, &block)
end
end
#__recursion_guard__ = nil
super(meth)
end
end)
yield
end
end
I just slapped this together, there's probably a lot that can be improved (e.g. use Refinements) and simplified.

Passing variables between classes in Ruby

I am trying to figure out how to pass variables between classes in Ruby. The example I am working on now is a game, where the players health, equipment, etc keeps changing and is passed from scene to scene until the game is over. Here is what I have so far:
class Player
def enter()
end
end
class MyPlayer < Player
def initialize()
dog_biscuits = false
end
end
class Scene
def enter()
end
end
class Entrance < Scene
def enter(player)
puts "You are in the entrance"
if player.dog_biscuits == false
puts "You don't have any biscuits."
end
end
end
player = MyPlayer.new
entrance = Entrance.new
entrance.enter(player)
Whenever I run this, I get the following error message:
entrance.rb:20:in `enter': undefined method `dog_biscuits' for #<MyPlayer:0x007fbfe2167f20> (NoMethodError)
I am running ruby 2.2.3p173 on OSX El Capitan.
Do this:
class MyPlayer < Player
attr_accessor :dog_biscuits
def initialize()
#dog_biscuits = false
end
end
Using attr_accessor will allow you to set and get instance variables. Remember also that you have to prefix instance variables with #.
class MyPlayer < Player
def initialize()
#dog_biscuits = false
end
def has_no_dog_biscuits?
#dog_biscuits == false
end
end
It is better to create method has_no_dog_biscuits? then to have attr_reader and to expose attribute to outer world, this way, you can always check if player has not dog_biscuits.

Why I cannot mixin an assignment method from a module

Suppose I have a module like this:
module MyAssigments
def dummy_assignment=(value)
puts "it's not assigned #{value}"
end
end
and a class that includes it like this:
class MyClass
include MyAssigments
def x=(value)
dummy_assignment=(value)
end
end
then
o = MyClass.new
o.x="anything"
does not print anything on screen, why ?
Ruby has a syntax/paring quirk here: using an assginemnt method for self has to be explicitly qualified thus:
def x=(value)
self.dummy_assignment=value
end
without the self. part, it is assumed by ruby to be an assignment to a local variable.

Ruby: How to hook a callback through inheritance

I've got some troubles with Ruby about callbacks (and inheritance). Here is my code:
class Lmao
def initialize
#str = "HAHAHAHAHAHHAHAHAH"
#before_laughing = []
end
def self.inherited(base)
base.extend(Callbacks)
end
def laughing
#before_laughing.each {|method| send(method) }
#str
end
end
module Callbacks
def before_laughing(*methods)
#before_laughing = methods
end
end
class Lol < Lmao
before_laughing :downcase_please
def downcase_please
#str.downcase!
end
end
a = Lol.new
a.laughing # => "HAHAHAHAHAHHAHAHAH"
And as you can see, my before laughing callback don't work... because the array #before_laughing is empty. I believe this can be fixed by editing the way I save *methods into an Lol's instance method (from inside Callbacks). But I don't really see how...
If you know the solution, thanks for your light!
Thanks to Mon_Ouie, the solution is:
class Lmao
def initialize
#str = "HAHAHAHAHAHHAHAHAH"
end
def self.inherited(base)
base.extend(Callbacks)
end
def laughing
self.class.callbacks_before_laughing.each {|method| send(method) }
#str
end
end
module Callbacks
def before_laughing(*methods)
#before_laughing = methods
end
def callbacks_before_laughing
#before_laughing
end
end
class Lol < Lmao
before_laughing :downcase_please
def downcase_please
#str.downcase!
end
end
Pretty awesome.
There are two different instance variables called #before_laughing in your code: one is an instance variable of instances of the Lmao class, which gets initialized to [] (i.e. an empty Array) in Lmao's initialize instance methods and gets read in Lmao's laughing instance method. However, since the only place this instance variable gets written to is the initializer, it will always be an empty Array.
The other instance variable is an instance variable of the Lol class object itself, which gets set to the Array [:downcase_please] inside of the before_laughing method. This one, however, never gets read.

Resources