Is there a Rails 3 replacement for subclasses_of? - activerecord

I am trying to get all derived classes for a specific type. In Rails 2+, you can say:
Class.subclasses_of SomeClass
This is because activesupport/lib/active_support/core_ext/object/extending.rb is gone in Rails 3.
Is there a replacement in Rails 3? Are there alternatives.

If you want to get all the subclasses of SomeClass, then you do:
SomeClass.descendants
Likewise, if you want to find out the parent classes, use:
SomeClass.ancestors
This will pass you back an Array for your consumption. Thus allowing you to:
SomeClass.descendants.each { |klass| }

There's always the option to search the ObjectSpace - something like:
classes = []
ObjectSpace.each_object(Class) do |klass|
SomeClass > klass
end
Which is a little wonky but useful. With more context, maybe there's a better approach?

Perhaps I misunderstand your question. I never used the subclasses_of method in Rails 2. In Rails 3 I just use Foo.descendants which provides an array of classes (and their attributes) that inherit from Foo. Very handy.

Related

Ruby: understanding data structure

Most of the Factorybot factories are like:
FactoryBot.define do
factory :product do
association :shop
title { 'Green t-shirt' }
price { 10.10 }
end
end
It seems that inside the ":product" block we are building a data structure, but it's not the typical hashmap, the "keys" are not declared through symbols and commas aren't used.
So my question is: what kind of data structure is this? and how it works?
How declaring "association" inside the block doesn't trigger a:
NameError: undefined local variable or method `association'
when this would happen on many other situations. Is there a subject in compsci related to this?
The block is not a data structure, it's code. association and friends are all method calls, probably being intercepted by method_missing. Here's an example using that same technique to build a regular hash:
class BlockHash < Hash
def method_missing(key, value=nil)
if value.nil?
return self[key]
else
self[key] = value
end
end
def initialize(&block)
self.instance_eval(&block)
end
end
With which you can do this:
h = BlockHash.new do
foo 'bar'
baz :zoo
end
h
#=> {:foo=>"bar", :baz=>:zoo}
h.foo
#=> "bar"
h.baz
#=> :zoo
I have not worked with FactoryBot so I'm going to make some assumptions based on other libraries I've worked with. Milage may vary.
The basics:
FactoryBot is a class (Obviously)
define is a static method in FactoryBot (I'm going to assume I still haven't lost you ;) ).
Define takes a block which is pretty standard stuff in ruby.
But here's where things get interesting.
Typically when a block is executed it has a closure relative to where it was declared. This can be changed in most languages but ruby makes it super easy. instance_eval(block) will do the trick. That means you can have access to methods in the block that weren't available outside the block.
factory on line 2 is just such a method. You didn't declare it, but the block it's running in isn't being executed with a standard scope. Instead your block is being immediately passed to FactoryBot which passes it to a inner class named DSL which instance_evals the block so its own factory method will be run.
line 3-5 don't work that way since you can have an arbitrary name there.
ruby has several ways to handle missing methods but the most straightforward is method_missing. method_missing is an overridable hook that any class can define that tells ruby what to do when somebody calls a method that doesn't exist.
Here it's checking to see if it can parse the name as an attribute name and use the parameters or block to define an attribute or declare an association. It sounds more complicated than it is. Typically in this situation I would use define_method, define_singleton_method, instance_variable_set etc... to dynamically create and control the underlying classes.
I hope that helps. You don't need to know this to use the library the developers made a domain specific language so people wouldn't have to think about this stuff, but stay curious and keep growing.

What if objects can print themselves in Ruby? [Object#print]

I was thinking wouldn't it be cool to have a print method defined in the Ruby Object class? Consider the following:
class Object
def print
puts self.to_s
end
end
23.times &:print
Is there any issue in having something like this? Seems like a good feature to have. It also appears easy to read.
There's already Object#inspect defined. Plus, there's already Kernel#print defined as private method in Object class and every class that inherits from it.
This method already exists in the Ruby standard library. However, it has a different name: display.
23.times &:display
# 012345678910111213141516171819202122
As you can see, it does not write a newline after the object's string representation; it is ill-suited for object inspection.
The main issue with adding methods to Object is that they become universal and may clash with similarly named methods in other libraries or in your project.
There are already multiple simple ways to output data or convert to string form in Ruby core, so the risk of a clash (on a very useful method name) likely outweighs any benefits from nicer syntax even in your own code.
If you have a smaller set of classes in your own project, where you feel this would be a useful feature to have, then this is an ideal use case for mix-ins.
Define a module:
module CanPrintSelf
def print
puts self.to_s
end
end
And include it in any class you want to have the feature:
class MyClass
include CanPrintSelf
end
my_object = MyClass.new
my_object.print
So you can have this feature if you like it, and you don't need to modify Object.

Monkey patching built-in ruby classes in limited scopes

I'm working on an internal Ruby DSL and to make it look as pretty as possible I need to monkey patch the Symbol class and add some operators. I want to be responsible in how I do this and would like to limit the scope and lifetime of the patches to a specific block of code. Is there a standard pattern for doing this? Here's some pseudo-code to show what I'm thinking:
class SomeContext
def self.monkey_patch_region(&block)
context = SomeContext.new
context.monkey_patch_Symbol
context.instance_eval(&block)
context.unmonkey_patch_Symbol
end
# magical method
def monkey_patch_Symbol
#...
end
# another magical method
def unmonkey_patch_Symbol
#...
end
end
I believe, that you're looking for ruby refinements. The feature has landed in ruby trunk, but it might be reverted before 2.0
I've heard about mixology gem. It was designed to mixin and unmix modules. Maybe it can be useful to monkey and unmonkey patches.
UPDATE: mixology won't help you, as it (un)mixes modules to objects (as with extend), not to classes (as with include), and you want monkey/unmonkey core classes, not their objects individually. Anyway I intend to maintain this answer as possibly useful reference for someone else.

Ruby - remove inherited methods

Is it possible to remove some of the inherited methods in Ruby? I mean, I can override it, but is there any other way?
Class ABC
end
a = ABC.new
puts a.id
Here, the method id is inherited from Object along with other methods like tap,class,type etc. I want to remove such methods.
Edit: I'm using Ruby 1.8.7
Yes - undef_method :foo will prevent any calls to the method foo (contrasted with remove_method :foo, which removes the method from the child, but still passes through up the inheritance chain).
Once again, though, why do you want to remove things like id?
You can always create a blank slate class to derive from:
class BlankSlate
instance_methods.each do |m|
undef_method(m) unless (m.match(/^__/))
end
end
This should strip out all methods except for the internal ones that you're not supposed to mess with, like __send__.
As tadman said you can make a BlankSlate object, or in ruby 1.9, there is the BasicObject class that has a bare minimum of methods. A quick google search turned up this for further reading: http://www.humbug.in/docs/ruby-best-practices/I_sect13_d1e2654.html
It appears that Rails already has BlankSlate built in: http://rubydoc.info/docs/rails/2.3.8/BlankSlate

Ruby - how to handle problem of subclass accidentally overriding superclass's private fields?

Suppose you write a class Sup and I decide to extend it to Sub < Sup. Not only do I need to understand your published interface, but I also need to understand your private fields. Witness this failure:
class Sup
def initialize
#privateField = "from sup"
end
def getX
return #privateField
end
end
class Sub < Sup
def initialize
super()
#privateField = "i really hope Sup does not use this field"
end
end
obj = Sub.new
print obj.getX # prints "i really hope Sup does not use this field"
The question is, what is the right way to tackle this problem? It seems a subclass should be able to use whatever fields it wants without messing up the superclass.
EDIT: The equivalent example in Java returns "from Sup", which is the answer this should produce as well.
Instance variables have nothing to do with inheritance, they are created on first usage, not by some defining mechanism, therefore there is no special access control for them in language and they can not be shadowed.
Not only do I need to understand your
published interface, but I also need
to understand your private fields.
Actually this is an "official" position. Excerpt from "The Ruby Programming Language" book (where Matz is one of the authors):
... this is another reason why it is only safe to extend Ruby
classes when you are familiar with
(and in control of) the implementation
of the superclass.
If you don't know it inside and out you're on your own. Sad but true.
Don't subclass it!
Use composition instead of inheritance.
Edit: Rather than MyObject subclassing ExistingObject, see if my_object having an instance variable referring to existing_object would be more appropriate.
Instance variables belong to instances (ie objects). They're not determined by the classes themselves.
unlike java/C#, in ruby private variables are always visible to the inheriting classes. There is no way to hide the private variables.
Ruby and Java don't treat 'private' property the same way. In Ruby if you mark something as private it only means that it can't be called with receiver, i.e.:
class Sub
private
def foo; end
end
sub.foo => error accessing private method with caller
but you can always access it if you change who is self like:
sub.instance_eval { foo } #instance_eval changes self to receiver, 'sub' in this example
Conclusion: Don't rely that you can hide or protect something from outer space! Or with great power comes great responsibility!
EDIT:
Yes, I know question was for fields but it's the same thing. You can always do:
sub.instance_eval { #my_private_field = 'something else' }
puts sub.instance_eval { #my_private_field }

Resources