customizing ruby .new operator - ruby

Let's say I have a class Foo and the constructor takes 2 parameters.
Based on these parameters the initialize method does some heavy calculations and stores them as variables in the instance of the class. Object created.
Now I want to optimize this and create a cache of these objects. When creating a new Foo object, I want to return a existing one from the cache if the parameters match. How can I do this?
I currently have a self.new_using_cache(param1, param2), but I would love to have this integrated in the normal Foo.new().
Is this possible in any way?
I can also deduct that using .new() combined with a cache is not really syntactical correct.
That would mean that the method should be called new_or_from_cache().
clarification
It's not just about the heavy calculation, it's also preferred because of limiting the amount of duplicate objects. I don't want 5000 objects in memory, when I can have 50 unique ones from a cache. So I really need to customize the .new method, not just the cached values.

class Foo
##cache = {}
def self.new(value)
if ##cache[value]
##cache[value]
else
##cache[value] = super(value)
end
end
def initialize(value)
#value = value
end
end
puts Foo.new(1).object_id #2148123860
puts Foo.new(2).object_id #2148123820 (different from first instance)
puts Foo.new(1).object_id #2148123860 (same as first instance)
You can actually define self.new, then call super if you actually want to use Class#new.
Also, this totally approach prevents any instantiation from ever occurring if a new instance isn't actually needed. This is die to the fact the initialize method doesn't actually make the decision.

Here's a solution I came up with by defining a generic caching module. The module expects your class to implement the "retrieve_from_cache" and "store_in_cache" methods. If those methods don't exist, it doesn't attempt to do any fancy caching.
module CacheInitializer
def new(*args)
if respond_to?(:retrieve_from_cache) &&
cache_hit = retrieve_from_cache(*args)
cache_hit
else
object = super
store_in_cache(object, *args) if respond_to?(:store_in_cache)
object
end
end
end
class MyObject
attr_accessor :foo, :bar
extend CacheInitializer
#cache = {}
def initialize(foo, bar)
#foo = foo
#bar = bar
end
def self.retrieve_from_cache(foo, bar)
# grab the object from the cache
#cache[cache_key(foo, bar)]
end
def self.store_in_cache(object, foo, bar)
# write back to cache
#cache[cache_key(foo, bar)] = object
end
private
def self.cache_key(foo, bar)
foo + bar
end
end

Something like this?
class Foo
##cache = {}
def initialize prm1, prm2
if ##cache.key?([prm1, prm2]) then #prm1, #prm2 = ##cache[[prm1, prm2]] else
#prm1 = ...
#prm2 = ...
##cache[[prm1, prm2]] = [#prm1, #prm2]
end
end
end
Edited
To not create an instance when the parameters are the same as before,
class Foo
##cache = {}
def self.new prm1, prm2
return if ##cache.key?([prm1, prm2])
#prm1 = ...
#prm2 = ...
##cache[[prm1, prm2]] = [#prm1, #prm2]
super
end
end
p Foo.new(1, 2)
p Foo.new(3, 4)
p Foo.new(1, 2)
# => #<Foo:0x897c4f0>
# => #<Foo:0x897c478>
# => nil

You could use a class-level instance variable to store results from previous object instantiations:
class Foo
#object_cache = {}
def initialize(param1, param2)
#foo1 = #object_cache[param1] || #object_cache[param1] = expensive_calculation
#foo2 = #object_cache[param2] || #object_cache[param2] = expensive_calculation
end
private
def expensive_calculation
...
enf
end

As you probably know you have reinvented the factory method design pattern and it's a perfectly valid solution using your name for the factory method. In fact, it's probably better to do it without redefining new if anyone else is going to have to understand it.
But, it can be done. Here is my take:
class Test
##cache = {}
class << self
alias_method :real_new, :new
end
def self.new p1
o = ##cache[p1]
if o
s = "returning cached object"
else
##cache[p1] = o = real_new(p1)
s = "created new object"
end
puts "%s (%d: %x)" % [s, p1, o.object_id]
o
end
def initialize p
puts "(initialize #{p})"
end
end
Test.new 1
Test.new 2
Test.new 1
Test.new 2
Test.new 3
And this results in:
(initialize 1)
created new object (1: 81176de0)
(initialize 2)
created new object (2: 81176d54)
returning cached object (1: 81176de0)
returning cached object (2: 81176d54)
(initialize 3)

Related

How create Ruby Class with same object id

I need to create a class where if the attribute value is the same it does not generate a new object id, example:
result:
described_class.new('01201201202')
<PixKey:0x00007eff5eab1ff8 #key="01201201202">
if i run it again with the same value it should keep the same object id
0x00007eff5eab1ff8
is similar behavior with the symbol
test:
describe '#==' do
let(:cpf) { described_class.new('01201201202') }
it 'verifies the key equality' do
expect(cpf).to eq described_class.new('01201201202')
end
end
Running the test shows an error, because the obejct id changes:
expected: #<PixKey:0x00007eff5eab1ff8 #key="01201201202">
got: #<PixKey:0x00007eff5eab2070 #key="01201201202">
Class:
class PixKey
def init(key)
#key = key
end
end
The other answers are fine, but they are a little more verbose than needed and they use class variables, which I find to be a confusing concept because of how they are shared among various classes.
class PixKey
#instances = {}
def self.new(id)
#instances[id] ||= super(id)
end
def initialize(id)
#key = id
end
end
p PixKey.new(1)
p PixKey.new(2)
p PixKey.new(2)
p PixKey.new(1)
Running the test shows an error, because the object id changes
Not quite. It shows an error because the objects are not equal. And the error message prints both objects including their id. But the object id is not what's causing the test to fail.
I need to create a class where if the attribute value is the same it does not generate a new object id
That would probably work, but you're likely approaching the problem from the wrong side. In Ruby, equality doesn't mean object identity. Two objects can be equal without being the same object, e.g.
a = 'foo'
b = 'foo'
a.object_id == b.object_id
#=> false
a == b
#=> true
There's no need to tinker with object ids to get your test passing. You just have to implement a custom == method, e.g.:
class PixKey
attr_reader :key
def initialize(key) # <- not "init"
#key = key
end
def ==(other)
self.class == other.class && self.key == other.key
end
end
The == method checks if both objects have the same class (i.e. if both are PixKey instances) and if their key's are equal.
This gives:
a = PixKey.new('01201201202')
b = PixKey.new('01201201202')
a == b
#=> true
Create a class method to create instances and have it look up a hash.
class PixKey
##instances = {}
def PixKey.create(id)
if not ##instances.has_key?(id)
##instances[id] = PixKey.new(id)
end
return ##instances[id]
end
def initialize(id)
#key = id
end
end
a = PixKey.new(123)
b = PixKey.new(123)
c = PixKey.create(123)
d = PixKey.create(123)
puts a
puts b
puts c
puts d
Output:
#<PixKey:0x000000010bc39900>
#<PixKey:0x000000010bc38078>
#<PixKey:0x000000010bc33eb0>
#<PixKey:0x000000010bc33eb0>
Notice the last two instances created with the PixKey.create(id) method return the same instance.
Note that Ruby's new method is just a method on Class and can be overridden like any other. The docs describe the default implementation.
Calls allocate to create a new object of class's class, then invokes that object's initialize method, passing it args. This is the method that ends up getting called whenever an object is constructed using .new.
So, if you want to keep the .new syntax and still get the same objects back, we can override new on the class and call super. This is exactly what OscarRyz' answer does, just with .new and super rather than a separate helper function.
class PixKey
##instances = {}
def PixKey.new(id)
if not ##instances.has_key?(id)
##instances[id] = super(id)
end
return ##instances[id]
end
def initialize(id)
#key = id
end
end
a = PixKey.new(123)
b = PixKey.new(123)
puts a
puts b

Is it possible to temporarily alter an instance variable for a chained method call?

I have a class that lazily loads data from a database into an instance variable, they are events in an array in numeric order. The class has several methods that analyse this array, here is an example of how I use it.
class Foo
def initialize
#a = [1,2,3,4,5] # data from database
end
def analyse
#a.reduce(:+)
end
end
d = Foo.new
result = d.analyse
I wanted to be able to apply these methods to the data after a very basic filter (eg: <= 3) and I imagined being able to call it like so:
d.at(3).analyse
and that the at method only affected the instance variable for the chained analyse call. i.e.
d = Foo.new # data loaded into instance var [1,2,3,4,5]
d.analyse # 15
d.at(3).analyse # 6
d.analyse # 15
I'm not sure how I can do this without re-creating a completely new object within the at call and this feels inefficient. I have a work around which would change how I call the at method - not the end of the world but I wondered if what I want is feasible whilst remaining efficient.
I'm not sure how I can do this without re-creating a completely new object within the at call and this feels inefficient.
I don't think creating a new object is too expensive. You could return a new Foo from at, initialized with a subset of the original data. You'd have another Foo instance and another Array instance, but the array would contain the very same objects:
class Foo
def initialize(a = nil)
#a = a || [1,2,3,4,5] # use a or fetch data from database
end
def analyse
#a.reduce(:+)
end
def at(max)
Foo.new(#a.take_while { |x| x <= max })
end
end
Example:
d = Foo.new
d.analyse #=> 15
d.at(3).analyse #=> 6
d.analyse #=> 15
You can prepare another instance variable which is set by at, overrides #a when defined, and is reset by analyse.
class Foo
def initialize
#a = [1,2,3,4,5]
end
def at i
#b = #a.select{|e| e <= i}
self
end
def array
if instance_variable_defined?(:#b)
#b.tap{remove_instance_variable(:#b)}
else
#a
end
end
def analyse
array.reduce(:+)
end
end

How to generate a random name in Ruby

I need to make a program in ruby to generate a robot name like KU765 or NG274 style
and to store them and check it to avoid repetition.
I also need to make a "reset" method to delete all stored names and start again.
This program is not working for some reason. I hope somebody helps me to find the mistake.
Thanks a lot.
class Robot
attr_accessor :named , :stored_names , :rl
def self.name
new.name
end
##rl = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def name
named = ""
named << ##rl[rand(26).to_i]
named << ##rl[rand(26).to_i]
named << rand(100..999).to_s
named.save_name
named.check_name
end
def save_name
stored_names = []
stored_names << named
end
def check_name
stored_names.uniq!
end
def reset
stored_names = Array.new
end
end
Here's another way to construct the Robot class that you may wish to consider. (My answers are not normally this long or detailed, but I wrote this in part to clarify aspects of Ruby's object model in my own mind. I hope it might help others do the same.)
Code
PREFACE = ('A'..'Z').to_a << ?_
SUFFIX = ('0'..'9').to_a
PREFACE_SIZE = 2
SUFFIX_SIZE = 3
class Robot
def self.reset() #bots = [] end
reset
def self.new() (#bots << super).last end
def self.bots() #bots end
def self.delete(bot) #bots.delete(bot) end
def self.bot_names() #bots.map { |b| b.name } end
attr_reader :name
def initialize() #name = add_name end
private
def add_name
loop do
#name = gen_name
return #name unless self.class.bot_names.include?(#name)
end
end
def gen_name
PREFACE.sample(PREFACE_SIZE).join << SUFFIX.sample(SUFFIX_SIZE).join
end
end
Example
Robot.bots #=> []
robbie = Robot.new #=> #<Robot:0x000001019f4988 #name="AP436">
robbie.name #=> "AP436"
Robot.bots #=> [#<Robot:0x000001019f4988 #name="AP436">]
r2d2 = Robot.new #=> #<Robot:0x000001019cd450 #name="KL628">
r2d2.name #=> "KL628"
Robot.bots #=> [#<Robot:0x000001019f4988 #name="AP436">,
# #<Robot:0x000001019cd450 #name="KL628">]
Robot.bot_names #=> ["AP436", "KL628"]
Robot.delete(robbie) #=> #<Robot:0x000001019f4988 #name="AP436">
Robot.bots #=> [#<Robot:0x000001019cd450 #name="KL628">]
Robot.bot_names #=> ["KL628"]
Robot.reset #=> []
c3po = Robot.new #=> #<Robot:0x000001018ff8c0 #name="VO975">
Robot.bots #=> [#<Robot:0x000001018ff8c0 #name="VO975">]
Explanation
When the class is parsed, the class method reset is first created, then the line reset is executed. As self => Robot when that occurs, the class method reset is executed, initializing #bots to an empty array.
The responsibility for saving and modifying a list of instances of Robot lies with the class. This list is held in the class instance variable #bots.
Instance of Robot are created by invoking Robot::new, which allocates memory and then invokes the (private) instance method initialize. Where is new? Since we have not defined it as a class method in Robot, there are two possibilities: it is inherited from one of Robot's ancestors (Robot.ancestors => [Robot, Object, Kernel, BasicObject]) or it is an instance method of the class Class, as that is the class for which Robot is an instance (i.e., Robot.class => Class) Let's find out which: Class.instance_method(:new) => #<UnboundMethod: Class#new> (or Class.instance_methods.include?(:new) => true), Object.method(:new) => #<Method: Class#new>. It's both! But that makes sense, because all classes are instances of Class, including Robot's superclass, Object. #<Method: Class#new> returned by Object.method(:new) shows new is defined in Class (which can alternatively be seen with Robot.method(:new).owner => Class. Very cool, eh? If you didn't know this already, and can follow what I've said in this paragraph, you've just learned the essence of Ruby's object model!
Suppose we add the class method new, shown below, to Robot. super invokes the class method Object::new (which is the instance method Class#new), passing any arguments of new (here there aren't any). Object::new returns the instance that it creates, which Robot::new in turn returns. Therefore, this method would simply be a conduit and and have no effect on the results.
def self.new
super
end
We can make a small change to the above method to add a copy of the instance that is created by Object::new to the array #bots:
def self.new
instance = super
#bots << instance
instance
end
I have written this a little more compactly as:
def self.new
(#bots << super).last
end
I've used the method Array#sample to randomly draw PREFACE_SIZE characters from PREFACE and SUFFIX_SIZE characters from SUFFIX_SIZE. sample samples without replacement, so you will not get, for example, "UU112". If you want to sample with replacement, replace the method gen_name with the following:
def gen_name
str = PREFACE_SIZE.times.with_object('') { |_,s| s << PREFACE.sample }
SUFFIX_SIZE.times { str << SUFFIX.sample }
str
end
I have created a class method bots to return the value of the class instance variable #bots. This could alternatively be done by defining a read accessor for #bots on Robots' singleton class:
class << self
attr_reader :name
end
When Robot.reset is invoked, what happens to all the instances of Robot it had contained? Will they be left to wander the forest, rejected and homeless? In languages like C you need to release their memory before casting them aside. In Ruby and many other modern languages that's not necessary (and generally can't be done). Ruby's "garbage collection" keeps track of all objects, and kills off (after releasing memory) any that are no longer referenced by any other object. Nice, eh?
The task itself is not hard, but I don't like the way your code is organised. This is what I would do in the first stage:
class Robot
class Name < String
class << self
def sign
"#{[*?A..?Z].sample}#{[*?A..?Z].sample}"
end
def number
"#{rand 1..9}#{rand 0..9}#{rand 0..9}"
end
def new
super << sign << number
end
end
end
end
And then:
Robot::Name.new
When constructing a list of names it is easy to check that they are unique. This is how I'd go about it:
class Robot
class Names < Array
def self.generate n
new.tap { |array| n.times do array.add_random_name end }
end
def add_random_name
name = Name.new
include?( name ) ? add_random_name : self << name
end
end
end
And then:
Robot::Names.generate 7
def save_name
stored_names = []
stored_names << named
end
Every time, you create a name, and call save_name you delete all previously created names, by assigning an empty array to stored_names
EDIT:
There were a few more errors, let me first post a working solution:
class Robot
attr_accessor :named , :stored_names , :rl
def initialize()
#stored_names = []
end
##rl = "_ABCDEFGHIJKLMNOPQRSTUVWXYZ".chars.to_a
def name
#named = ""
#named << ##rl.sample
#named << ##rl.sample
#named << rand(100..999).to_s
save_name
check_name
end
def save_name
#stored_names << #named
end
def check_name
#stored_names.uniq!
end
def reset
#stored_names = Array.new
end
end
To access the members of your object, you have to prefix them with #.
You called save_name and check_name on #named, which is a string and doesn't provide these methods
#stored_names must be initialized to an empty array, before you can push elements into it with <<. This is normally done in the class's constructor initialize()
I understand this isn't efficient, but this will work.
letters = [*'A'..'Z'] =>
numbers = [*100..999]
names = []
2.times{names.push(letters.shuffle.first)} => Randomizing array and choosing element
names.push(numbers.shuffle.first)
names.join => Creates a String object out of the array elements
This isn't pretty, but it gets the job done.
This is how I automate Cary's approach with my y_support/name_magic:
require 'y_support/all'
class Robot
★ NameMagic
def name_yourself
begin
self.name = "#{[*?A..?Z].sample( 2 ).join}#{rand 100..999}"
rescue NameError; retry end
end
end
3.times { Robot.new.name_yourself }
Robot.instances #=> [PR489, NS761, OE663]
Robot.forget "PR489"
Robot.instances #=> [NS761, OE663]
Robot.forget_all_instances
Robot.instances #=> []
Robot.new.name_yourself
Robot.instances #=> [IB573]

How deny creating instance variables in Ruby

I would like to deny creating instance variables in Ruby,to prevent unattended variables being created 'by mistake'.
My class:
class Test
def initialize
#a = 'Var A'
end
def make_new
#b = 'Var B' <-- I would like to deny creation of any variables that were not defined during the init
end
end
I don't claim this is a good idea, but just b/c it's kind of interesting, here is a solution that will throw an exception when a new ivar is created, but will also let you modify defined instance variables (unlike freezing the class). Just threw this together, there are undoubtably some issues w/ it, including the fact that it duplicates every method :)
module IvarBlocker
def method_added(method)
alias_name = "__#{method}_orig"
return if method == :initialize || method_defined?(alias_name) || method.match(/__.*_orig/)
alias_method alias_name, method
define_method(method) do |*args|
ivars_before = instance_variables.dup
send(alias_name, *args).tap { raise "New Ivar assigned" if !(instance_variables - ivars_before).empty? }
end
end
end
Usage
class Test
extend IvarBlocker
def initialize
#a = 1
end
def set_b
#b = 2
end
def set_a
#a = 6
end
end
t = Test.new #=> #<Test:0x007f87f13c41e8 #a=1>
t.set_b #=> RuntimeError: New Ivar assigned
t.set_a #=> 6
You can freeze object instances at the end of initialize method:
class Test
def initialize
#a = 'Var A'
freeze
end
def make_new
#b = 'Var B' # I would like to deny creation of any variables that were not defined during the init
end
end
t=Test.new
p t.instance_variable_get :#a
# "Var A"
t.make_new
#a.rb:24:in `make_new': can't modify frozen Test (RuntimeError)
# from a.rb:30:in `<main>'
t.instance_variable_set :#c, 'Var C'
# a.rb:31:in `instance_variable_set': can't modify frozen Test (RuntimeError)
# from a.rb:31:in `<main>'
class << t
#d = 'Var D'
end
#a.rb:33:in `singletonclass': can't modify frozen Class (RuntimeError)
# from a.rb:32:in `<main>'
p t.instance_variable_get :#d
There is a way - a hacky (but fun) way which is not meant for production (and is relatively slow). My sample implementation works for a single object only, but can be extended to support many objects.
Let's assume the following setup:
class Foo
def initialize
#a = :foo
end
def set_b; #b = 3; end
def set_c; #c = 7; end
end
def freeze_variables_of(obj)
frozen_variables = obj.instance_variables
set_trace_func lambda {|event, file, line, id, binding, classname|
if classname == obj.class
this = binding.eval 'self'
if this == obj
(this.instance_variables - frozen_variables).each {|var| this.remove_instance_variable var}
end
end
}
end
With the use of set_trace_func we can set a Proc which is called very often (usually more than once per statement). In that Proc we can check instance variables and remove unwanted variables.
Let's look at an example:
a = Foo.new
# => #<Foo:0x007f6f9db75cc8 #a=:foo>
a.set_b; a
# => #<Foo:0x007f6f9db75cc8 #a=:foo, #b=3>
freeze_variables_of a
a.set_c; a
# => #<Foo:0x007f6f9db75cc8 #a=:foo, #b=3>
We see that after doing the "freeze", set_c cannot set the instance variable (in fact the variable is removed at the very moment the set_c method returns).
In contrast to freezing the object (with a.freeze) (which I'd recommend for any real world application), this way allows you to modify all allowed instance variables while forbidding new ones.
This even works, if you directly assign instance variables (while Alex' method is probably faster, but relies on accessor methods).
There is no way to prevent creation of accidental instance variables defined that way. Why do you want to do this? What would you want such code to achieve?

Change the binding of a Proc in Ruby

I have this code:
l = lambda { a }
def some_function
a = 1
end
I just want to access a by the lambda and a special scope which has defined a already somewhere like inside some_function in the example, or just soon later in the same scope as:
l = lambda { a }
a = 1
l.call
Then I found when calling l, it is still using its own binding but not the new one where it was called.
And then I tried to use it as:
l.instance_eval do
a = 1
call
end
But this also failed, it is strange that I can't explain why.
I know the one of the solution is using eval, in which I could special a binding and executing some code in text, but I really do not want to use as so.
And, I know it is able to use a global variable or instance variable. However, actually my code is in a deeper embedded environment, so I don't want to break the completed parts if not quite necessary.
I have referred the Proc class in the documentation, and I found a function names binding that referred to the Proc's context. While the function only provided a way to access its binding but cannot change it, except using Binding#eval. It evaluate text also, which is exactly what I don't like to do.
Now the question is, do I have a better (or more elegant) way to implement this? Or using eval is already the regular manner?
Edit to reply to #Andrew:
Okay, this is a problem which I met when I'm writing a lexical parser, in which I defined a array with fixed-number of items, there including at least a Proc and a regular expression. My purpose is to matching the regular expressions and execute the Procs under my special scope, where the Proce will involved some local variables that should be defined later. And then I met the problem above.
Actually I suppose it is not same completely to that question, as mine is how to pass in binding to a Proc rather than how to pass it out.
#Niklas:
Got your answer, I think that is what exactly I want. It has solved my problem perfectly.
You can try the following hack:
class Proc
def call_with_vars(vars, *args)
Struct.new(*vars.keys).new(*vars.values).instance_exec(*args, &self)
end
end
To be used like this:
irb(main):001:0* lambda { foo }.call_with_vars(:foo => 3)
=> 3
irb(main):002:0> lambda { |a| foo + a }.call_with_vars({:foo => 3}, 1)
=> 4
This is not a very general solution, though. It would be better if we could give it Binding instance instead of a Hash and do the following:
l = lambda { |a| foo + a }
foo = 3
l.call_with_binding(binding, 1) # => 4
Using the following, more complex hack, this exact behaviour can be achieved:
class LookupStack
def initialize(bindings = [])
#bindings = bindings
end
def method_missing(m, *args)
#bindings.reverse_each do |bind|
begin
method = eval("method(%s)" % m.inspect, bind)
rescue NameError
else
return method.call(*args)
end
begin
value = eval(m.to_s, bind)
return value
rescue NameError
end
end
raise NoMethodError
end
def push_binding(bind)
#bindings.push bind
end
def push_instance(obj)
#bindings.push obj.instance_eval { binding }
end
def push_hash(vars)
push_instance Struct.new(*vars.keys).new(*vars.values)
end
def run_proc(p, *args)
instance_exec(*args, &p)
end
end
class Proc
def call_with_binding(bind, *args)
LookupStack.new([bind]).run_proc(self, *args)
end
end
Basically we define ourselves a manual name lookup stack and instance_exec our proc against it. This is a very flexible mechanism. It not only enables the implementation of call_with_binding, it can also be used to build up much more complex lookup chains:
l = lambda { |a| local + func(2) + some_method(1) + var + a }
local = 1
def func(x) x end
class Foo < Struct.new(:add)
def some_method(x) x + add end
end
stack = LookupStack.new
stack.push_binding(binding)
stack.push_instance(Foo.new(2))
stack.push_hash(:var => 4)
p stack.run_proc(l, 5)
This prints 15, as expected :)
UPDATE: Code is now also available at Github. I use this for one my projects too now.
class Proc
def call_with_obj(obj, *args)
m = nil
p = self
Object.class_eval do
define_method :a_temp_method_name, &p
m = instance_method :a_temp_method_name; remove_method :a_temp_method_name
end
m.bind(obj).call(*args)
end
end
And then use it as:
class Foo
def bar
"bar"
end
end
p = Proc.new { bar }
bar = "baz"
p.call_with_obj(self) # => baz
p.call_with_obj(Foo.new) # => bar
Perhaps you don't actually need to define a later, but instead only need to set it later.
Or (as below), perhaps you don't actually need a to be a local variable (which itself references an array). Instead, perhaps you can usefully employ a class variable, such as ##a. This works for me, by printing "1":
class SomeClass
def l
#l ||= lambda { puts ##a }
end
def some_function
##a = 1
l.call
end
end
SomeClass.new.some_function
a similar way:
class Context
attr_reader :_previous, :_arguments
def initialize(_previous, _arguments)
#_previous = _previous
#_arguments = _arguments
end
end
def _code_def(_previous, _arguments = [], &_block)
define_method("_code_#{_previous}") do |_method_previous, _method_arguments = []|
Context.new(_method_previous, _method_arguments).instance_eval(&_block)
end
end
_code_def('something') do
puts _previous
puts _arguments
end

Resources