How to Dynamically Define a Class Method Which Will Refer to a Local Variable Outside

How to dynamically define a class method which will refer to a local variable outside?

Class methods don't really exist in Ruby, they are just singleton methods of the class object. Singleton methods don't really exist, either, they are just ordinary instance methods of the object's singleton class.

Since you already know how to define instance methods (using Module#define_method), you already know everything you need to know. You just need to call class_eval on C's singleton class instead of C itself:

(class << C; self end).class_eval do
define_method(:a_class_method) do
puts var
end
end

Current versions of Ruby have a singleton_class method to make that easier:

C.singleton_class.class_eval do
define_method(:a_class_method) do
puts var
end
end

But actually, current versions of Ruby also have Module#define_singleton_method, so, in this particular case, that is unnecessary:

C.define_singleton_method(:a_class_method) do
puts var
end

How do I dynamically create class method by using a variable from outside a singleton class?

To accomplish what you want, you can do:

class MyClass
@@columns = ['col1', 'col2']

def self.create_methods
@@columns.each do |column_name|
define_method(column_name) { |column_name| puts column_name }
end

class << self
@@columns.each do |column_name|
define_method(column_name) { |col_name| puts "class_method defined" }
end
end
end
end

Note: Using def self."method_name" to define a class method let you to use instances variables (ie. @columns), that's why i redefined as class variable.

When you open the singleton class (class << self), you lose the previous scope, so you cant get column_name (Name Error). But have access to class variables.

In your case, use define_singleton_method. As follow:

class MyClass
@columns = ['col1', 'col2']

def self.create_methods
@columns.each do |column_name|
define_method(column_name) { |column_name| puts column_name }
define_singleton_method(column_name) { |col_name| puts "class_method defined" }
end
end
end

How can I dynamically create class methods for a class in python

You can dynamically add a classmethod to a class by simple assignment to the class object or by setattr on the class object. Here I'm using the python convention that classes start with capital letters to reduce confusion:

# define a class object (your class may be more complicated than this...)
class A(object):
pass

# a class method takes the class object as its first variable
def func(cls):
print 'I am a class method'

# you can just add it to the class if you already know the name you want to use
A.func = classmethod(func)

# or you can auto-generate the name and set it this way
the_name = 'other_func'
setattr(A, the_name, classmethod(func))

In Ruby, is there no way to dynamically define a local variable in the current context?

It seems that Ruby's magic would provide a way, but according to Matz, this was only possible in 1.8 via eval and only in certain contexts (i.e. irb). As of 1.9, this behavior was taken out ("strictly forbidden"):

Matz himself weighs in here: https://www.ruby-forum.com/topic/155673#685906

I read from somewhere that now Ruby can't dynamically create local variable. Is it true or just a bug?


The local variables are created in compile time, so that local
variables that are defined in eval() cannot be accessed outside of
eval. In 1.8, irb and tryruby does line by line compilation so that
local variables are spilled from eval(), but in 1.9, it's strictly
prohibited even under line-by-line compilation.

          matz.

(Non-sequitur alternative here, for anyone who wants something like this but not the exact technical situation that the questioner has):

Use a hash:

local_hash = {}

my_vars.each_pair do |k,v|
local_hash[k] = v
end

puts local_hash['foo']
#=> 'baz'

Objective-C class method local variables of type self

I understand what you're looking for, but there is no instanceof(self) pattern. The following achieves what you want, though admittedly doesn't have the elegance of typeof(self) pattern:

@interface Foo: NSObject
@property (nonatomic, copy) NSString *string;
@end

@implementation Foo
+ (instancetype)fooWithString:(NSString *)string {
Foo *foo = [[self alloc] init];
foo.string = string;
return foo;
}
@end

@interface Foobar: Foo
// perhaps some more properties here
@end

@implementation Foobar
// and perhaps some more methods here
@end

This implementation demonstrates that the convenience method still allows subclassing. I.e., you can do:

Foobar *foobar = [Foobar fooWithString:@"baz"];

And the resulting object will be a Foobar instance.

How to define methods dynamically inside a python class?

This is one of the classic Python stumbles. Your get the value of the variable, and the variable ends up with the final value.

You can do what you want by "capturing" the value of the variable as a default:

        for method_name in method_names:
def _f(method=method_name):
print(method)

Getting local variable names defined inside a method from outside the method

You can (re)-parse the method and inspect the S-EXPR tree. See below for a proof of concept. You can get hold of the file where the method is defined using Method#source_location and then read that file. There is surely room for improvement to my code but should get you started. It is a fully functional piece of code and only requires the ruby parser gem (https://github.com/whitequark/parser).

require 'parser/current'
node = Parser::CurrentRuby.parse(DATA.read) # DATA is everything that comes after __END__

def find_definition(node, name)
return node if definition_node?(node, name)
if node.respond_to?(:children)
node.children.find do |child|
find_definition(child, name)
end
end
end

def definition_node?(node, name)
return false if !node.respond_to?(:type)
node.type == :def && node.children.first == name
end

def collect_lvasgn(node)
result = []
return result if !node.respond_to?(:children)

node.children.each do |child|
if child.respond_to?(:type) && child.type == :lvasgn
result << child.children.first
else
result += collect_lvasgn(child)
end
end

result
end

definition = find_definition(node, :foo)
puts collect_lvasgn(definition)

__END__

def foo
var = 100
arr = [1,2]
if something
this = 3 * var
end
end

def bar
var = 200
arr = [3, 4]
end

Do you mind telling us WHY you want to find the variables?

How to dynamically open a class so to add to it a scope method that makes use of a local variable?

counter_cache_column is a local variable. Local variable are local to the scope they are defined in (that's why they are called local variables).

In this case, the scope is the block passed to included.

The class definition and the method definition create a new empty scope. Only blocks create nested scopes, so, you need to use a block to defined your method. Thankfully, there is a way to do so: by passing a block to define_method:

module MyModule
extend ActiveSupport::Concern

included do
klass = get_class_name.constantize # => User
counter_cache_column = get_counter_cache # => "counter_count"

klass.define_singleton_method(:order_by_counter) {
order("#{counter_cache_column} DESC")
}
end
end

I made some other style improvements:

  • self is the implicit receiver in Ruby, there is no need to specify it
  • CLASS_NAME is misleading: it doesn't contain the name of the class, it contains the class itself
  • also, I don't see why it would need to be a constant

How to dynamically create local and global variables?

You cannot define a local variable with a full stop (.) character in ruby. That is not valid syntax.

(eval):2: unexpected fraction part after numeric literal
string_1.0 = "1.0"

Additionally, you cannot dynamically define local variables. There are various workarounds to sort-of achieve this, however, fundamentally I think you are asking an XY problem.

For example, have you considered using an OpenStruct, or passing this hash as locales when rendering a template, or instead dynamically setting instance variables?



Related Topics



Leave a reply



Submit