I would like to make something like this:
class Result<<ActiveRecord::Base
def condensation
#some code here that calculates #winner and #looser and #condresalut
def winner
#winner
end
def looser
#looser
end
def showresault
#condresalut
end
end
end
so that I can call res.condensation.winner and res.condensation.looser and res.condensation.showresault.
What is the best way to do it? Apparently this way it does not work, I got nils.
It is indeed possible to do so. Not sure what the intent is, as that has been asked, but not sure if that question was clarified.
However Jay Fields has a well visited blog entry that shows how to define a method inside a method.
class Class
def def_each(*method_names, &block)
method_names.each do |method_name|
define_method method_name do
instance_exec method_name, &block
end
end
end
end
Your methods themselves inside your definition though are likely better served using the attr_reader technique.
As far as calling nested defined methods:
def testing
def testing2
'it worked'
end
end
puts testing::testing2
Thogh as Alex D reminds me in the comments, the scope operator is a deception.
I don't think you can get there from here.
Ruby allows us to define methods inside methods, but the inner methods are not exposed, or available directly.
The inner methods are only available from within the outer method, so, in your example, winner, looser and showresault are only accessible from inside condensation.
You could create lambdas or procs and return them, en masse, as closures, which would give you access to the internal values inside condensation, but, really, it seems as if you're confusing the use of a class vs. a method and trying to make a method behave like a class with its accessors. Instead, I'd probably create a class within a class, and go from there.
def condensation
#condensation ||= Struct.new(:winner, :looser, :showresult).new
end
def winner
#winner ||= condensation.winner
end
def winner=(winner)
#winner = winner
end
... and so on
I changed resault by result, and I wanted to change showresult with show_result
You can calculate winner like this:
def calculate_winner
# something using winner= method
end
Related
I apologize up front. I'm going to struggle articulating this question.
TL;DR - I have an object I'm using to call a method in the subclass. That method needs access to a method in a parent class (forcing inheritance...read below). I'm thinking this won't work because I'm instantiating the subclass, so the inheritance won't work right, but I'm not sure. I'm still seeking out documentation. Basically, the method in the parent class is not "seen" the way I'm doing this - NoMethodError is the exception.
I prefer DRY code, as most people do. I usually use compositing in lieu of inheritance in my code, but I think I'm at a point where if I want to keep this DRY, I have to use inheritance (though I could be wrong, so I'm open to suggestions), and so I'm trying it out, which leads me to this question.
Given the following Ruby "pseudo" code or example to kind of demonstrate what I'm trying to accomplish:
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
end
end
And then in a different file, same module
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method
# things get done and then
method_i_want_to_use(arg1, args) ## <<=== fails
end
end
end
Yet in another file
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method
#my_obj.my_other_method
end
end
end
So one important thing I missed. The method method_i_want_to_use is a method that is used all over the place in my code. It just so happens that in this one class, inheritance was NOT originally used because this class is basically atomic with the exception of this one method. So my problem is either I copy the method into this class and use it (but that kinda breaks the DRY principle sorta) or I find a way to share this method between classes.
This gets into OOP design pretty heavily and I am aware of that. One could ask: well, is the inheritance as it currently sits even relevant to the objects in question? Yes...and no. They can be. In short, principally, it works, but frankly, I don't like it. TBH, I almost prefer to just copy the method into the "subclass" and remove the inheritance and be done with it, but DRY -- unless I'm going a little too wild with DRY in this context and I kinda think I am.
Anyway, just curious what folks with more knowledge than I have for me on this. This really is the first time I've dabbled this deeply into inheritance. :)
I'd love pointers on how I can keep from implementing
There are two different methods here:
an instance method:
def method_i_want_to_use(arg1, *args)
# does all the things
end
and a class method:
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.class.method_i_want_to_use(arg1, arg)
end
but what you probably want in this case is
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
There are a few choices and it depends on what method_i_want_to_use is doing. Is it a separate thing? Then you can call it as a class method ParentClass.method_i_want_to_use inside the SubClass without inheritance.
Another way is to define it in a module and include it
include ModuleX
# and then in your code
method_i_want_to_use(...)
I'd use inheritance if you want to have some kind of common abstraction layer and you expect multiple subclasses to behave the same way. If the classes/objects that need to use method_i_want_to_use have different behaviours then inheritance is not the correct choice. Let's say you have a class that send a request to a 3rd party API and you have a class that does saves records to your db. For some reason you need to use the same piece of code (a method) in both cases, maybe to calculate some value. Using inheritance to include the method would be a mistake, because both classes have different behaviours.
Hope that helps.
After fixing some of the syntax errors and changing the call self.class.method_i_want_to_use to self.new.method_i_want_to_use as Adam also mentioned in his answer, this code seems to work fine.
I did not get any undefined methods until I tried to call SomeModule::ParentClass.method_i_want_to_use(3,4) and that was fixed by the change from class to new. Are you sure your undefined method error was not related to that?
module SomeModule
class ParentClass
def initialize
end
def method_i_want_to_use(arg1, *args)
# does all the things
puts "here #{arg1} , #{args}"
end
def self.method_i_want_to_use(arg1, *args)
arg = args.first unless args.empty?
self.new.method_i_want_to_use(arg1, arg)
end
end
end
module SomeModule
class SubClass < ParentClass
def initialize
end
# this isn't working
def my_other_method(arg1, arg2)
# things get done and then
method_i_want_to_use(arg1, arg2) ## <<=== fails
end
end
end
module SomeModule
class Thing
def initialize
#my_obj = SubClass.new
end
def my_method(arg1,arg2)
#my_obj.my_other_method(arg1, arg2)
end
end
end
SomeModule::Thing.new.my_method(1,2)
SomeModule::ParentClass.method_i_want_to_use(3,4)
prints:
here 1 , [2]
here 3 , [4]
First of all, this is really just a golf question. My code works fine as it is. But I feel like there is probably a better (i.e. cooler) way to do this.
So I've got a class that acts a lot like a hash. However, it really internally generates a hash for each call to its hash-ish methods. The private method for generating that hash is calculated(). So my code currently has a lot of method definitions like this:
def each(&block)
return calculated.each(&block)
end
def length()
return calculated.length
end
Is there a concise way to delegate all those method calls to the calculated method?
I figured it out and it's incredibly simple. Just delegate to the name of the method. Here's a working example:
class MyClass
extend Forwardable
delegate %w([] []=) => :build_hash
def build_hash
return {'a'=>1}
end
end
edit: don't do this; I forgot Forwardable existed
You can write a "macro" for this. Well, Ruby doesn't technically have actual "macros" but it's a fairly common pattern nonetheless. Rails in particular uses it extensively - stuff like belongs_to, validates, etc are all class methods which are being used to generate instance-level functionality.
module DelegateToFunc
def delegate_to_func(delegate, delegators)
delegators.each do |func_name|
# Note: in Ruby 2.7 you can use |...| instead of |*args, &blk|
define_method(func_name) do |*args, &blk|
send(delegate).send(func_name, *args, &blk)
end
end
end
end
class SequenceBuilder
extend DelegateToFunc
delegate_to_func(:calculated, [:length, :each])
attr_accessor :min, :max
def initialize(min:, max:)
#min, #max = min, max
end
def calculated
min.upto(max).to_a
end
end
SequenceBuilder.new(min: 5, max: 10).length # => 6
SequenceBuilder.new(min: 1, max: 4).each { |num| print num } # => 1234
I will say, though, that methods generated by metaprogramming can sometimes be hard to track down and can make a program confusing, so try and use them tastefully ...
For example, do you really need your object to expose these hash-like methods? Why not just let the caller read the hash via calculated, and then call the hash methods directly on that?
The Problem
There is a pattern that I find myself to be frequently using, so I'd like to dry it up. I have stuff like this:
class InfoGatherer
def foo
true
end
def people
unless #people
#people = # Long and complex calculation (using foo)
end
#people
end
end
I'd like to dry this up to look like this:
class InfoGatherer
extend AttrCalculator
def foo
true
end
attr_calculator(:people) { # Long and complex calculation (using foo) }
end
To accomplish this, I defined a module AttrCalculator to extend into InfoGatherer. Here's what I tried:
module AttrCalculator
def attr_calculator(variable_name_symbol)
variable_name = "##{variable_name_symbol}"
define_method variable_name_symbol do
unless instance_variable_defined?(variable_name)
instance_variable_set(variable_name, block.call)
end
instance_variable_get(variable_name)
end
end
end
Unfortunately, when I try something as simple as InfoGatherer.new.people, I get:
NameError: undefined local variable or method `foo' for InfoGatherer:Class
Well, that's odd. Why is block running in the scope of InfoGatherer:Class, rather than its instance InfoGatherer.new?
The Research
I know I can't use yield, because that would try to catch the wrong block, as seen here.
I attempted to use self.instance_exec(block) in the place of block.call above, but then I received a new error:
LocalJumpError: no block given
Huh? I see the same error in this SO question, but I'm already using bracket notation, so the answers there don't seem to apply.
I also tried to use class_eval, but I'm not sure how to call block inside of a string. This certainly doesn't work:
class_eval("
def #{variable_name_symbol}
unless #{variable_name}
#{variable_name} = #{block.call}
end
#{variable_name}
end
")
That use case is called memoization. It can be done easily like:
def people
#people ||= # Long and complex calculation (using foo)
end
You shouldn't go into the mess like you are.
The problem was that, inside the define_method, self was surprisingly InfoGatherer, rather than an instance of InfoGatherer. So I was on the right track with self.instance_exec(block).
The working solution is self.instance_exec(&block) (note the ampersand). I guess the interpreter doesn't recognize that block is a block unless you label it as such? If anyone can explain this better than me, please do.
As a side note, this is not the best way to solve this particular problem. See #sawa's answer for a clean way to memoize complicated calculations.
To expand on the last persons
def people(varariable = nil)
#people ||= ComplexCalculation.new(variable).evaluate
end
class ComplexCalculation
def initialize(variable)
#variable = variable
end
def evaluate(variable)
#stuff
end
end
By extracting this class you are isolating that complexity and will have a much better experience.
There has got to be a more efficient way to do this in Ruby. I have a list of methods that scrape the same things (title, price) across multiple sites but in slightly different ways based on the code in each store. For example:
def store1_get_title
def store1_get_price
def store2_get_title
def store2_get_price
def store3_get_title
def store3_get_price
When calling all of these functions, I would just like a generic call with say a "namespace" parameter to do invoke any of these methods without having to type out all of them, something like:
for get_all_stores().each do |store|
store::get_title
store::get_price
end
...which would invoke store1_get_title, store1_get_price, store2_get_title, store2_get_price like I want. Is there something like this or a better way to do this?
Hope that makes sense. Thanks for any input!
Edit: these tasks are in rake task code.
This is a perfect use for classes. If you find two stores with the same software powering them (maybe Yahoo commerce or EBay stores) you can make instances of the classes with different parameters.
class Amazon
def get_price; end
def get_title; end
end
class Ebay
def initialize seller; end
def get_price; end
def get_title; end
end
[Amazon.new, Ebay.new("seller1"), Ebay.new("seller2")] each do |store|
store.get_price
store.get_title
end
And you can do this in any other object-oriented language by defining a base class or interface that all of the stores implement/inherit.
I don't understand the logic of your application. Perhaps you should think about a class definition (see Ken Blooms answer).
Nevertheless you could try a dynamic call with send:
def store1_get_title
p __method__
end
def store1_get_price
p __method__
end
def store2_get_title
p __method__
end
def store2_get_price
p __method__
end
def store3_get_title
p __method__
end
def store3_get_price
p __method__
end
all_stores = ['store1', 'store2', 'store3']
all_stores.each do |store|
send("#{store}_get_title")
send("#{store}_get_price")
end
You didn't define what get_all_stores returns. In my example I used Strings. You could add some syntactical sugar and extend String (I don't recommend this)
class String
def get_title()
send("#{self}_get_title")
end
def get_price()
send("#{self}_get_price")
end
end
all_stores.each do |store|
store.get_title
store.get_price
end
One last remark. You wrote
for get_all_stores().each do |store|
each alone should be enough. for is not ruby-like and in combination with each it doen't look reasonable to me.
Is there a quick way to track the methods that are being called on an object? Often, when I'm working with a gem at a level just below their public interface, I run into errors that are hard to track down. Ultimately, I end up tracking the object through the source code and keeping everything in my head.
But it would be nice to be able to call something like a #log_method_calls on an object so that, say, all methods called on it get printed to stdout or something. Is there any way to accomplish this?
There are several methods to do it, depending on the situation.
If it' possible to create a new object instead of the observed, you can easily write an observer class using method_missing.
class LogProxy
def initialize obj
#obj = obj
end
def method_missing(name, *args)
puts "#{name} => #{args.to_s}"
#desk.send(name, *args)
end
end
If it's not possible, you still may use alias_method. It's a bit more tricky, but using Module.instance_methods you can chain every method of anything.
Something like:
module Logger
def self.included(mod)
mod.instance_methods.each do |m|
next if m =~ /with_logging/
next if m =~ /without_logging/
mod.class_eval do
define_method "#{m}_with_logging" do |*args|
puts "#{m} called #{args.to_s}"
self.send_without_logging "#{m}_without_logging", *args
end
alias_method "#{m}_without_logging", m
alias_method m, "#{m}_with_logging"
end
end
end
end
TargetClass.send(:include, Logger)