Add Existing Classes into a Module

Add existing classes into a module

Use the const_missing hook. If the constant can't be found in the current module, try to resolve in the global namespace:

class A; end
class B; end

module M
def self.const_missing(c)
Object.const_get(c)
end
end

M::A.new
M::B.new

Add Ruby classes to a module when defined in separate files

The accepted practice in this case is to wrap every file in module block

# a/b.rb
module A
class B

end
end

# a/c.rb
module A
class C

end
end

Btw. because of the way constant are resolved, it is advisable to use the long form I quoted above instead class A::B

(http://blog.honeybadger.io/avoid-these-traps-when-nesting-ruby-modules/).

Add class to existing modules (external library)

Here is the solution

import 'phaser-ce';

declare global {
module Phaser {
module Physics {
class Box2D {
prop: number;
// Constructor declaration matters
constructor(param: WhateverType);
}
}
}
}

Phaser.Physics.Box2D = class {
public prop = 42;
constructor(private param: WhateverType) {}
};

Add class to ruby module in runtime

This question is concerned specifically with adding a class at runtime. The class is to be created within an existing module, but, as will be seen, that is almost incidental and is of questionable utility.

Adding a class to a module at runtime

To assist in the construction of classes within a given module at runtime we might construct a method class_factory.

def class_factory(mod, class_name, consts, meths, instance_meths,
accessors)
class_obj = mod.const_set(class_name, Class.new)
consts.each { |const,val| class_obj.const_set(const,val) }
meths.each do |name,body|
class_obj.singleton_class.
instance_eval("define_method(:#{name}) #{body}")
end
instance_meths.each do |name,body|
class_obj.instance_eval("define_method(:#{name}) #{body}")
end
accessors.each do |accessor,inst_var|
class_obj.public_send(accessor, inst_var)
end
class_obj
end

Let's try it.

module M
end

class_obj = class_factory(
M,
"B",
{ 'A'=>7, 'D'=>'cat' },
{ greeting: '{ |n| "Cat\'s have #{n} lives" }' },
{ initialize: '{ |name| @name = name }',
say_name: '{ "My name is #{@name}" }' },
{ attr_accessor: "name" }
)
#=> M::B

class_obj == M::B
#=> true
M::B.constants
#=> [:A, :D]
class_obj.methods(false)
#=> [:greeting]
M::B.instance_methods(false)
#=> [:say_name, :name=, :name]
class_obj.greeting(9)
#=> "Cat's have 9 lives"
M::B.greeting(5)
#=> "Cat's have 5 lives"

instance = M::B.new "Lola" # or class_obj.new "Lola"
#=> #<M::B:0x000056cb6e766840 @name="Lola">
instance.say_name
#=> "My name is Lola"
instance.name
#=> "Lola"
instance.name = "Lo"
#=> "Lo"
instance.name
#=> "Lo"

It could be that your code may contain static expressions such as these, and the only dynamic part is the construction of the class.

On the other hand, the class may be used dynamically as well. For example:

mod = "M"
cl = "B"
name = "Lola"
meth = "say_name"

Then:

Object.const_get("#{mod}::#{cl}").new(name).public_send(meth)
#=> "My name is Lola"

or

class_obj.new(name).public_send(meth)
#=> "My name is Lola"

How best to reference dynamically-created classes

We have just seen various ways to reference a dynamically-created class. Depending on requirements, M::B versus class_obj and Object.const_get("#{mod}::#{cl}") versus class_obj. Clearly, the use of class_obj is simplest in both cases and has the additional advantage that references to class_obj need not be changed if, in future, M or B in M::B are changed.

Are the advantages to creating classes dynamically that are members of a module?

Recall that the main reason to create a class within a module is create a namespace, so that, for example, M1::C and M2::C do not create a name conflict. However, if we reference a dynamically-created class by its (unique) object (rather than its name, a constant) that is held by a variable (here class_obj) there is no need for the namespace. So the answer to the question I posed in this section is "no".

Moreover, if we reference a dynamically-created class by its object, there is no reason to assign a name to the class. We therefore could modify class_factory as follows:

def class_factory(consts, meths, instance_meths, accessors)
Class.new do
consts.each { |const,val| const_set(const,val) }
meths.each do |name,body|
singleton_class.
instance_eval("define_method(:#{name}) #{body}")
end
instance_meths.each do |name,body|
instance_eval("define_method(:#{name}) #{body}")
end
accessors.each do |accessor,inst_var|
public_send(accessor, inst_var)
end
end
end

class_obj = class_factory(
{ 'A'=>7, 'D'=>'cat' },
{ greeting: '{ |n| "Cat\'s have #{n} lives" }' },
{ initialize: '{ |name| @name = name }',
say_name: '{ "My name is #{@name}" }' },
{ attr_accessor: "name" }
)
#=> #<Class:0x000056cb6eaeefd0>

The object held by class_obj is called an anonymous class because it has no name (that is a constant).

class_obj.constants
#=> [:A, :D]
class_obj.methods(false)
#=> [:greeting]
class_obj.instance_methods(false)
#=> [:say_name, :name=, :name]

instance = class_obj.new "Billy-Bob"
#=> #<#<Class:0x000056cb6eaeefd0>:
# 0x000056cb6eb183d0 @name="Billy-Bob">
instance.say_name
#=> "My name is Billy-Bob"
instance.name
#=> "Billy-Bob"
instance.name = "BB"
#=> "BB"

How to add functions from modules to a class at runtime while preserving the package hierarchy?

These kind of hierarchy definitions are a bit unusual in python projects, which is why you're having a hard time implementing it with the everyday-syntax. You should take a step back and think about how invested into this architecture you really are, and if it isn't too late to rewrite it in a way that adheres more closely to common python idioms, maybe you should do that instead ("explicit is better than implicit" in particular comes to mind).

That being said, if everyday python doesn't cut it, you can use strange python to write what you want without too much of a hassle. Consider reading up on the descriptor protocol if you want to understand how functions are turned into methods in detail.


MyFunPackage/worlds/__init__.py

from . import world1, world2

This line needs to be updated for any new world_n.py file you create. While it can be automated to import dynamically, it will break any IDE's member hinting and requires even more shifty code. You did write that you don't want to change anything else when adding modules, but adding the name of the file to this line is hopefully ok.

This file should not contain any other code.

MyFunPackage/worlds/world*.py

def frobulate(self):
return f'{self.name} has been frobulated'

There is no need to add any special code to world1.py, world2.py, or any of the new files in the worlds folder. Just write your functions in them as you see fit.

MyFunPackage/helloworlds.py

from types import MethodType, FunctionType, SimpleNamespace

from . import worlds

_BASE_ATTRIBUTES = {
'__builtins__', '__cached__', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__path__', '__spec__'
}

class Worlds:
def __init__(self, name):
self.name = name

# for all modules in the "worlds" package
for world_name in dir(worlds):
if world_name in _BASE_ATTRIBUTES:
continue # skip non-packages and
world = getattr(worlds, world_name)
function_map = {}

# collect all functions in them, by
for func in dir(world):
if not isinstance(getattr(world, func), FunctionType):
continue # ignoring non-functions, and
if getattr(world, func).__module__ != world.__name__:
continue # ignoring names that were only imported

# turn them into methods of the current worlds instance
function_map[func] = MethodType(getattr(world, func), self)

# and add them to a new namespace that is named after the module
setattr(self, world_name, SimpleNamespace(**function_map))

The module addition logic is completely dynamic and does not need to be updated in any way when you add new files to worlds.


After setting it up as a package and installing it, trying your example code should work:

>>> from MyFunPackage.helloworld import Worlds
>>> x = Worlds('foo')
>>> x.world1.frobulate()
'foo has been frobulated'

Thanks python, for exposing your internal workings so deliberately.


Tangent: Dynamically adding functions to objects, patching vs describing

Using types.MethodType to turn a function into a method configures said descriptor protocol on it, and passes ownership of the function to the owning instance. This is preferable to patching the instance into the signature due to a number of reasons.

I'll give an example real quick, because I think this is good to know. I'll skip the namespace here, since it doesn't change the behavior and would just make it a little harder to read:

class Foo:
"""An example class that does nothing yet."""
pass

def bar(self, text: str) -> str:
"""An example function, we will add this to an instance."""
return f"I am {self} and say {text}."

import inspect
import timeit
import types
# now the gang's all here!

Patching with a lambda

>>> foo = Foo()
>>> foo.bar = lambda *args, **kwargs: bar(foo, *args, **kwargs)
>>> foo.bar('baz')
'I am <__main__.Foo object at 0x000001FB890594E0> and say baz.'
# the behavior is as expected, but ...

>>> foo.bar.__doc__
None
# the doc string is gone
>>> foo.bar.__annotations__
{}
# the type annotations are gone
>>> inspect.signature(foo.bar)
<Signature (*args, **kwargs)>
# the parameters and their names are gone
>>> min(timeit.repeat(
... "foo.bar('baz')",
... "from __main__ import foo",
... number=100000)
... )
0.1211023000000182
# this is how long a single call takes
>>> foo.bar
<function <lambda> at 0x000001FB890594E0>
# as far as it is concerned, it's just some lambda function

In short, while the base functionality is reproduced, a lot of information is lost along the way. There is a good chance that this will become a problem down the road, whether because you want to properly document your work, want to use your IDE's type hinting, or have to go through stack traces during debugging and want to know which function exactly caused problems.

While it's completely fine to do something like this to patch out a dependency in a test suite, it's not something you should do in the core of your codebase.

Changing the descriptor

>>> foo = Foo()
>>> foo.bar = types.MethodType(foo, bar)
>>> foo.bar('baz')
'I am <__main__.Foo object at 0x00000292AE287D68> and say baz.'
# same so far, but ...

>>> foo.bar.__doc__
'An example function, we will add this to an instance.'
# the doc string is still there
>>> foo.bar.__annotations__
{'text': <class 'str'>, 'return': <class 'str'>}
# same as type annotations
>>> inspect.signature(foo.bar)
<Signature (text: str) -> str>
# and the signature is correct, without us needing to do anything
>>> min(timeit.repeat(
... "foo.bar('baz')",
... "from __main__ import foo",
... number=100000)
... )
0.08953189999999722
# execution time is 25% lower due to less overhead, no delegation necessary here
>>> foo.bar
<bound method bar of <__main__.Foo object at 0x00000292AE287D68>>
# and it knows that it's a method and belongs to an instance of Foo

Binding a function as a method in this way retains all information properly. As far as python is concerned, it is now the same as any other method that was bound statically and not dynamically.

Add class methods to an existing module in ruby

Finally managed to make it work by myself.

Please tell me if this is a good or a bad practice :

module SomeModule

def self.included(base)
base.send(:extend, ClassMethods)
end

module ClassMethods

def my_original_method
end

# Some methods

end

end

module MyNewModule

def self.included(base)
base.class_eval do

class << self

alias_method :old_included, :included

def included(base)
old_included(base)
base.send(:extend, ClassMethods)
end

end

end
end

module ClassMethods

def my_method
end

end

end

SomeModule.send(:include, MyNewModule)

class Pouet

include SomeModule

my_original_method
my_method

end

Add classes to project after compile time

Sure. What you're looking for is the reflection API.

For example:

String cName = askUserForClass();
assert cName.equals("com.foo.schreiber.PriceyModule");
Class<?> moduleClass = Class.forName(cName);
MyModule mm = (MyModule) moduleClass.getConstructor().newInstance();

and now you have a variable of type MyModule. You can just invoke m1 on this, assuming m1 is in MyModule and MyModule is in the base version (that's how you should be setting this up).

Note, of course, that com.foo.schreiber.PriceyModule does need to be on the classpath of the JVM for this to work. If it is not, this answer is going to grow about 3 pages worth, to set up a class loader, set up loading parentages so that you share the MyModule definition, and a whole lotta code to reliably find the jar or whatever it might be that is the source of the extra module. So, you know. Would be a lot simpler if you can just ensure it's on the classpath. As long as its in the jar, that'll be the case.

How to create a class in one module(A) that implements an abstract class from another module(B)

It sounds like you're in over your head on microservices here, but, in the interests of answering the question as stated:

Think 'twitter API'. Twitter has 2 'projects' (not in the git submodule sense, in the english word sense). There's twitter-the-website, which is non-public code that runs it all, notably including the code that answers when you connect to api.twitter.com. But there's also an open source (or at least, publicly available) library that you can include in your java projects that lets you talk to the twitter API. This public API includes model classes that match concepts in the twitterverse (such as 'a tweet', 'a user', 'a direct message', 'the concept of one user deciding to follow another', etc), as well as functions (presumably on an 'api' object) that you call with parameters and which returns instances of these model classes.

You need to do the same thing. A microservice consists of two projects: Its API which another microservice includes in itself, which is analogous to the public 'java API' library that twitter offers, and the actual code. Which could be one project or a million, a significant part of the point of microservices is: From the point of view of microservice A that depends on microservice B, you don't need to know anything about B at all except the part that describes its public API. Everything else is an implementation detail that just doesn't matter, as far as service A is concerned.

If you included all the code of a microservice in another, then you end up with every 'microservice' including all code of all others, and there's nothing micro about your services anymore.

Yes, this is annoying. You don't exactly need to duplicate code (the 'public API' part that defines the models can also be a dependency of the microservice itself), but every microservice turns into maintaining 2 separate ones, and you need to find a way for the 'public API' part to be distributable as if it was the twitter API. You probably don't want to put it on maven central, but that's why maven (sonatype, really), gradle, etc all offer the notion of a company-wide intermediate dependency server - that one can host your 'public API' projects. As well as local dependencies - read the docs of your build system on how to deal with non-open-source-publicized (I.e. not on maven central) dependencies.



Related Topics



Leave a reply



Submit