Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
Abstract class looks in Ruby code like an alien from remote planet Java. I'm trying to collect Ruby tricks which can substitute this unwanted pattern.
Let's take a completely random example:
class AbstractRace < Struct.new(:runner_count)
def go!
runner_count.times.map do |index|
Thread.new do
run(index)
end
end.each(&:join)
end
def run(index)
raise 'To be implemented in derivative classes'
end
end
class RunnerRace < AbstractRace
def run(index)
puts "I am runner number #{index}. I am running"
end
end
class CarRace < AbstractRace
def run(index)
puts "I am car number #{index}. I am accelerating"
end
end
RunnerRace.new(2).go!
CarRace.new(2).go!
How to rewrite it? A possible approach would be using a mixin, like this:
require 'active_support/concern'
module Race
extend ActiveSupport::Concern
def go!
participant_count.times.map do |index|
Thread.new do
run(index)
end
end.each(&:join)
end
module ClassMethods
def configure_race(methods)
[:participant_count, :run].each do |method_symbol|
define_method method_symbol, methods[method_symbol]
end
end
end
end
class RunnerRace < Struct.new(:runner_count)
include Race
configure_race participant_count: ->() { runner_count },
run: ->(index) { puts "I am runner number #{index}. I am running" }
end
class CarRace < Struct.new(:car_count)
include Race
configure_race participant_count: -> { car_count },
run: ->(index) { puts "I am car number #{index}. I am going" }
end
RunnerRace.new(2).go!
CarRace.new(2).go!
What other solutions could be? Is there a common idiom for such case?
Why not just take advantage of the fact that Ruby is a dynamic language?
class Race
attr_reader :participants
def initialize(participants)
#participants = participants
end
def go!
participants.each_with_index.map do |index,participant|
Thread.new do
participant.run(index)
end
end.each(&:join)
end
end
class CarEntry
def run(index)
puts "I am car number #{index}. I am going"
end
end
There is no need for anything running in a 'race' to extend a superclass. All anything in the race must do is be capable of racing i.e having a
run(index)
method that does something.
In ruby I would tend to think of 'AbstractRace' as more of a role for a class to play. Roles are best encapsulated in modules (as you've suggested in your first response).
If you are trying to come up with a general ruby solution, however, I would recommend removing the reference to ActiveSupport::Concern. This module is something that comes from Rails and may not be available in all ruby environments.
There is nothing wrong with what you have written there and I'm not entirely sure what you are unhappy with.
That being said, this is Ruby and there is no need to define the run method on your AbstractRace class. If that's what is bothering you, then just don't do it.
The reason you put it there is to show both yourself and other developers who might be working on the code that a Race should have a run method. It's defining the interface. It definitely is not required though, but it is the "proper" way to make an object oriented class hierarchy.
I think you're missing the point of abstract classes
Languages like Java use abstract classes because they want to:
Collect common code for derived classes in one place (common base class), and
Prevent instantiating this common base class, because it is a base class.
If you wanted to achieve the same goals, you could do this by:
Creating a base class with the common code
Giving it a private constructor:
```
class AbstractRace
private:
def initialize
end
end
```
The other reason people use abstract classes, is the same as interfaces: they want to guarantee that some method exists on a derived class.
Unfortunately, there's no such construction as Ruby; in fact, this is "un-Ruby-like." In Ruby, we rely on "duck typing," which means "if it quacks, it's a duck!" Observe:
class Car
def drive
return 'VROOOM!'
end
end
class Duck
def quack
return 'Quack quack!'
end
end
test_objs = [Car.new, Duck.new]
test_objects.each do |some_obj|
if some_obj.respond_to?(:quack)
puts "#{some_obj} is a duck! #{some_obj.quack}"
else
puts 'Not a duck, sorry.
end
end
This will output something like <Duck:0x123456> is a duck! Quack quack!
This is relying on "duck typing," by checking for the existence of methods before using them. This is the closest idiom in Ruby.
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]
I was recently sifting through some code and came across something like this:
class A
##container = {}
def self.register(a, b)
##container[a] = b
end
def self.get(a)
##contaienr[a]
end
end
class BRunner < A
A.register(D, self)
def self.run
#...
end
end
class CRunner < A
A.register(E, self)
def self.run
#...
end
end
class C
def self.call
[D, E].each do |item|
A.get(item).run()
end
end
end
BRunner and CRunner call register when their respective class definition blocks are executed at runtime. Then, when class C is ran explicitly, it calls what D and E are mapped to, and call the run function This doesn't seem right because to me, this is not clear code. Is this a Ruby thing or just bad programming?
Your example, while it is Ruby code, doesn't appear to be a Ruby specific design pattern. I suspect it's a software design pattern someone created for that codebase.
Without context of the actual codebase it's difficult to say whether it's too abstract or "bad", but it's likely there is room for improvement even within the small example you provided.
You can find examples of common software design patterns written in Ruby for comparison:
https://bogdanvlviv.com/posts/ruby/patterns/design-patterns-in-ruby.html
https://github.com/davidgf/design-patterns-in-ruby
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
We're using feature flags in order to enable/disable certain features in our system.
I had a discussion with my colleague over what's the standard way of adding feature flags to the code itself:
Consider the following method:
def featured_method
do_this
do_that
end
The method is being called from about 15 different places inside our code.
Would you recommend adding the check if the feature is enabled before every call to this method:
if feature_enabled?(:feature_key)
featured_method
end
Or inside the featured_method itself, like this:
def featured_method
if feature_enabled?(:feature_key)
do_this
do_that
end
end
The advantage of having the condition inside the method itself is obvious: DRYing up the code, and the fact that when you want to add the feature permanently, you simply remove the condition from within the method.
The advantage of having the condition before every call is that it is very clear whether that method gets executed or not without going into the featured_method code itself, which can save quite a lot of headaches.
I was wondering if there's another solution or a standard for those kind of issues.
I would merge both approaches.
This would lead to DRY code on the callers side. It would not violate the SRP in the feature_method and it would clearly communicate what is going on - if you can find a better name than me:
def may_execute_featured_method
featured_method if feature_enabled?(:feature_key)
end
def featured_method
do_this
do_that
end
The caller would use may_execute_featured_method
I would be tempted to split feature keying out into its own module, and use it like this:
class Foo
include FeatureKeyed
def foo
'foo'
end
feature_keyed :foo
def bar
'bar'
end
feature_keyed :bar
end
foo = Foo.new
p foo.foo # => "foo"
p foo.bar # => FeatureKeyed::FeatureDisabled
Here's the module:
module FeatureKeyed
class FeatureDisabled < StandardError ; end
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def feature_keyed(method_name, feature_key = method_name)
orig_method = instance_method(method_name)
define_method method_name do |*args|
raise FeatureDisabled unless feature_enabled?(feature_key)
orig_method.bind(self).call *args
end
end
end
def feature_enabled?(feature_key)
feature_key == :foo
end
end
Notes:
feature_enabled? hard-codes the eneabled feature names. You would change that.
This code raises an exception if a feature is disabled. The code in your question simply returns. Do what makes sense for your application. If you need different "not enabled" behavior for different methods, then the behavior could be passed to feature_keyed.
method _feature_keyed_ will take a second argument which is the feature key. If missing, the name of the method is used as the feature key.
Is there a practical application to the "crazy-ness" below?
It seems like this is a way for ted to always be able to return himself to the world and people will think they are talking to ted who they expect to act a certain way and be a certain age... but he isn't acting the way he portrays himself and is lying about his age to someone.
What 'trickery' is possible when an object is returned and you check on what that object represents and is capable of... but really that object was acting another way and capable of other things before returning.
class Person
def age
21
end
def who_am_i?
puts "I am #{self} / #{object_id} and I am #{age} years old"
self
end
end
ted = Person.new
def ted.singleton_who_am_i?
class << self
def age
0
end
end
puts "I am #{self} / #{object_id} and I am #{age} years old"
self
end
puts ted.who_am_i? == ted.singleton_who_am_i?
>> I am #<Person:0x100138340> / 2148123040 and I am 21 years old
>> I am #<Person:0x100138340> / 2148123040 and I am 0 years old
>> true
http://andrzejonsoftware.blogspot.ca/2011/02/dci-and-rails.html
in DCI, your data model gets different type of behavior based on the context it is used it. Usually it is done with object.extend, but it is pretty much what you are doing above -- taking advantage of the metaclass.
Another example (and probably why things work that way) is the way classes work in ruby. If you say
class Foo
end
that is the same thing as saying
Foo = Class.new
end
meaning that what you are doing is assigning a new instance of class Class to a constant. When you define a method on that class, you don't want it applied to all instance of class Class, you only want it on the class you are defining. So when you say
class Foo
def self.bar
end
end
it is the exact thing as saying
class Foo
end
def Foo.bar
end
which is exactly the same principal as you are talking about in your question
(sorry if that was unclear)
Ruby is a very dynamic language letting you inject code into objects at runtime. There are some good uses for it but it can also make code very hard to debug and understand.
It's totally counter-intuitive for a method that queries an object to modify that object. Nobody would expect a call to who_am_i to modify the object.
On the other hand replacing methods like that can make unit testing classes really straight forward.
If you want to test how the class behaves with different ages you can inject code like that before your tests.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why isn't the eigenclass equivalent to self.class, when it looks so similar?
class << self idiom in Ruby
I have this class:
class Player < ActiveRecord::Base
before_save :set_slug
def remains
((end_date - Date.today) + 1).to_i
end
def self.url
"Our_link_#{slug}"
end
class << self
def load_track_lists
#do somthing
end
end
end
and I understand the class and instance methods but the
class << self
def load_track_lists
#do somthing
end
end
is really confusing. What is it and how does it differ from the prior two methods?
The end result is basically the same as if it had been defined as
def self.load_track_lists
#do somthing
end
There are subtle differences between the two methods if you're doing more than just defining methods in the class << self block, as described in the linked question, but effectively you're "opening up" the current class to define class level methods in it.
It doesn't differ from the self.url method. It's basically a container that allows you to put multiple methods without having to put self. in front of the method name. Probably not useful in the example but can be quite clean for other classes.
IMO it's a developer's preference