Ruby loop through instance methods and run them - ruby

I have the following class:
module StatCalculators
class Passing
def initialize(user_id, game_id)
#user_id = user_id
#game_id = game_id
end
def save_completion_percentage
completions = StatType.find_by_name("Completions").stats.where(athlete_id: #user_id).sum(:float_value)
attempts = StatType.find_by_name("Pass Attempts").stats.where(athlete_id: #user_id).sum(:float_value)
value = completions/attempts
stat = Stat.new(value: value, game_id: #game_id, athlete_id: #user_id, float_value: value)
stat.save(validate: false)
end
end
end
The class above has the potential to have a lot more methods that need to be run without having to call each method individually... is there a way to run all instance methods in the initialize method?

It is possible:
module StatCalculators
class Passing
def initialize(user_id, game_id)
#user_id = user_id
#game_id = game_id
klass = self.class
klass.instance_methods(false).each do |method|
klass.instance_method(method).bind(self).call
end
end
...
end
end

Related

I need to override pundit scope but I don't know how to

I have a question about Pundit.
Basically I want to do this:
class Scope < Scope
def resolve
scope.select {|employee| (employee.restaurant == #restaurant) && employee.actif}
end
end
but I don't know how I can pass #restaurant from my controller into my policy.
here's my index method:
def index
#restaurant = Restaurant.find(params[:restaurant_id])
#employees = policy_scope(Employee)
end
I tried to do this:
class Scope
attr_reader :user, :scope, :record
def initialize(user, scope, record)
#user = user
#scope = scope
#record = record
end
def resolve
if is_user_manager_or_gerant_or_admin?
scope.select {|employee| (employee.restaurant == record) && employee.actif}
end
end
private
def is_user_manager_or_gerant_or_admin?
user.admin || (user.accreditations.select {|a| a.restaurant == record})[0].role == ("GĂ©rant" || "Manager")
end
end
with this index method:
def index
#restaurant = Restaurant.find(params[:restaurant_id])
#employees = EmployeePolicy::Scope.new(current_user, Employee, #restaurant).resolve
end
But I'm getting this error:
Pundit::PolicyScopingNotPerformedError in EmployeesController#index
It's not clear from your question where you put the Scope class, but it should live inside your EmployeePolicy class. You'll pass in a parameter just like you would to any other class.
I think you are getting this error because you are inadvertently converting your ActiveRecord scope to an Array by using the #select method. Try using ActiveRecord methods instead.
# app/policies/employee_policy.rb
class EmployeePolicy < ApplicationPolicy
class Scope
attr_reader :user, :scope, :restaurant
def initialize(user, scope, restaurant)
#user = user
#scope = scope
#restaurant = restaurant
end
def resolve
if is_user_manager_or_gerant_or_admin?
scope.where(restaurant: restaurant).where.not(employee.actif: nil)
end
end
...
end
end
Your index method should look like this:
# app/controllers/employees_controller.rb
class EmployeesController < ApplicationController
def index
#restaurant = Restaurant.find(params[:restaurant_id])
#employees = EmployeePolicy::Scope.new(current_user, Employee, #restaurant).resolve
end
end
If you are still having trouble, then this post may be instructive.

Is it possible to access a method without creating an instance?

I have a class within a module and it has methods:
module D
class Dog
#name = 'pluto'
def setName( n )
#name = n
end
def getName ()
return #name
end
end
end
Can I access getName without creating an instance of Dog like the static method in C++? Something like:
D::Dog.getName ()
instead of:
d = D::Dog.new
d.getName()
I believe you're looking for what is known as a class method in Ruby:
module SomeModule
class SomeClass
#class_variable = "some_string" # An instance variable on a class
def self.some_class_method
#class_variable # Return can be omitted in Ruby
end
# This is how setter methods are usually written in Ruby
def self.some_class_method= new_value
#class_variable = new_value
end
end
end
SomeModule::SomeClass.some_class_method
#=> "some_string"

Set class variable from define_method inside self.method_added

I would like to count method calls of new methods defined in a class. To do this, I redefine each newly defined method using method_added hook. Inside it, I use define_methodand increment the value of a class variable##test_count`.
Base class:
class Unit
#new_method = true
##test_count = 0
def self.test_count
puts ##test_count
end
def self.method_added(name)
old_method = instance_method(name)
if #new_method
#new_method = false
define_method(name) do |*args, &block|
##test_count += 1
old_method.call(*args, &block)
end
#new_method = true
end
end
end
Subclass with newly defined methods:
class Test < Unit
def test_assertion
puts true
end
end
When I call a new method, ##test_count is still 0:
Test.new.test_assertion
Unit.test_count
true
0
Why ##test_count value isn't changed?
The problem was caused by initializing class instance variable #new_method in the body of class Unit. As I was subclassing this class with Test this variable was not initialized in subclass Test. No ideas why it's like that but I solved the problem by changing if to unless thus using nil from uninitialized variable to pass the check and then assign appropriate values to it:
class Unit
##test_count = 0
def self.method_added(name)
unless #new_method
#new_method = true
old_method = instance_method(name)
define_method(name) do |*args, &block|
##test_count += 1
old_method.bind(self).call(*args, &block)
end
#new_method = false
end
end
end
Any ideas why class instance variable initialization isn't "inherited" in a subclass?

Ruby - Calling a method from a child object

I'm new to Ruby and trying to determine how I can call a class from a child object. Something like the below; however when I try it, I get an error saying "undefined local variable or method `me'"
class my_object < Object
attr_accessor :me
def initialize(attributes ={})
end
def setvalue(passed_value)
#passed_value = passed_value.to_s
end
def search(passed_value)
#passed_value.include?(passed_value)
end
end
def getMe
me_too = my_object.new
me_too.me = "test"
me_too.me.search("test")
end
end
instance.class
will give you a reference to the class
This works:
But your code had multiple errors.
class MY
attr_accessor :me
def initialize(attributes ={})
end
def setvalue(passed_value)
passed_value = passed_value.to_s
end
def search(passed_value)
passed_value.include?(passed_value)
end
def getMe
me_too = MY.new
me_too.me = "test"
me_too.search("test")
end
end
my = MY.new
my.getMe
You don't need to explicity extend Object, everything extends Object in ruby.
Your class name needs to start with a capital letter.
class MyObject
attr_accessor :me
end
me_too = MyObject.new
me_too.me = "test"
in console
me_too => #<MyObject:0x106b2e420 #me="test">
Check out some introductory ruby tutorials maybe http://ruby.learncodethehardway.org/

How to get the instance in ruby?

I have such a case:
class Person
#a class that wraps to some db table
def initialize(attributes=nil)
populate_with_attributes(attributes) if !attributes.nil?
end
def self.find(id)
#the_db.execute('query here where id....')
end
def save
#save logic and queries here
#the_db.execute('save query here')
end
# other methods .....
end
class SuperPerson
#another class that wraps to some db table
end
class SpTh < Thread
def initialize(thread_id, *other_params)
super
#thread_id = thread_id
#db = SQLite3.Database.new("./db_#{#thread_id}.sqlite3")
#....
end
def start
person = Person.find(55)
person.age = 27
person.save
end
# other methods .....
end
class Sp
def initialize
#threads_amount = 5
#threads = []
#...
raise_threads
#...
end
def raise_threads
#threads_amount.times{|thread_id|
#threads << SpTh.new(thread_id, *other_params){}
}
end
# other methods .....
end
My problem is:
How do I set the value of the #the_db variable in the Person and SuperPerson classes to the value of #db from SpTh class so that each thread has its own database?
You're accessing the class's #the_db from both the instance (in save) and the class (in self.find): wrap it in a class method, so from the instance you can access it on the class by calling self.class.connection (see the db method):
class Person
def self.connect(connection)
#the_db = connection
end
def self.connection
#the_db
end
def self.find(id)
#the_db.execute("...")
end
def db
self.class.connection
end
end
You can use singleton classes to set different connections:
db = SQLite3.Database.new("./db_#{#thread_id}.sqlite3")
person_class = Class.new(Person){ self.connect(db) }
person_class.find(1)

Resources