I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).
I tried overriding instance_variable_set but see that that's not how
Ruby actually sets values and is just a programmatic helper method for
working with an instance.
So, does anybody know how to intercept assigning values to instance
variables? Thanks.
This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.
What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.
- A
···
On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
So, does anybody know how to intercept assigning values to instance
variables?
You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).
This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.
···
On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:
I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).
You may want to look into Aspect Oriented Programming, unfortunately I
don't have any experience with AOP in ruby so I can't recommend any
frameworks.
···
On Thu, Mar 19, 2015 at 3:14 PM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).
I tried overriding instance_variable_set but see that that's not how
Ruby actually sets values and is just a programmatic helper method for
working with an instance.
So, does anybody know how to intercept assigning values to instance
variables? Thanks.
--
Darryl L. Pierce <mcpierce@gmail.com> http://mcpierce.blogspot.com/
Famous last words:
"I wonder what happens if we do it this way?"
My project (Qpid Proton) involves wrapping a C messaging library in Ruby
(and Perl, but that's another story).
With our current "reactive" APIs, we have a C engine called the reactor
that sends fires events on state changes. From the C code it has a
reference to Ruby objects (not actual objects, that's another story as
well) that it wants to notify on these events.
So, for example, I create an instance of Qpid::Proton::Connection. It
has a Ruby-wrapped reference to a C struct (its impl) and it's that impl
that gets notified by the reactor when the connection's state changes.
When that bubbles up into the Ruby VM space, I want to be able to
recreate that instance of Connection (since the original Ruby object may
have been garbage collected). So I want to store the state values for
that object in the Proton library's record store (third, and last, long
story).
In Python we're able to do this easily. The Python Connection class
extends a class called Wrapper that overrides __getattr__ and
__setattr__ and backs it with a dict that is stored in that record
store. So if you change state info on a Connection in Python, those
changes are stored and can be fetched later to recreate that Connection
object. (remember: the impl is a C struct and never gets destroyed even
when the Ruby or Python object that used it goes away)
Does that get across the problem I'm trying to solve?
···
On Thu, Mar 19, 2015 at 12:56:25PM -0400, Alex Chaffee wrote:
On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
> So, does anybody know how to intercept assigning values to instance
> variables?
This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.
What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.
--
Darryl L. Pierce <mcpierce@gmail.com>
Famous last words:
"I wonder what happens if we do it this way?"
Hi Ryan, can you help to know how to understand code challenges?
···
Sent from my iPhone
On Mar 19, 2015, at 1:49 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:
On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:
I'm developing some code that needs to intercept when an instance
variable is set for a class. It needs to be arbitrary; i.e., I don't
want to have to have code declare variables differently than they do now
and I don't want them to have to create mutator methods (since it needs
to intercept non-public values as well).
You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).
This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.
2015-03-19 17:56 GMT+01:00 Alex Chaffee <alex@stinky.com>:
On Thu, Mar 19, 2015 at 10:14 AM, Darryl L. Pierce <mcpierce@gmail.com> > wrote:
> So, does anybody know how to intercept assigning values to instance
> variables?
This may be impossible (though I'm happy to be proven wrong). Ruby
stores instance data inside C structures that are accessed
more-or-less directly from many places in the Ruby interpreter. See Ruby Internals | PPT (slide 16
especially) or Pat Shaughnessy if
you want the nasty details.
What are you trying to accomplish? Maybe some smart person on this
list can help you come up with a different strategy.
Hrm, I hadn't quite thought of it like that; i.e., discouraging using @
instance variables in code that uses our library. I was hoping to make
the code work as unobtrusively as possible. But you make a great point
that, by encouraging this sort of pattern, it gives us more ability to
enhance the library over time.
···
On Thu, Mar 19, 2015 at 01:49:32PM -0700, Ryan Davis wrote:
> On Mar 19, 2015, at 07:14, Darryl L. Pierce <mcpierce@gmail.com> wrote:
>
> I'm developing some code that needs to intercept when an instance
> variable is set for a class. It needs to be arbitrary; i.e., I don't
> want to have to have code declare variables differently than they do now
> and I don't want them to have to create mutator methods (since it needs
> to intercept non-public values as well).
You can't, at least not without some serious C-level hacking. There are no hooks for such a thing (there are hooked variables that you can trace, but they're all globals).
This is a big reason why my code has as few "@"s as possible. Wrapping an accessor method is a lot simpler than hooking into the runtime itself.
--
Darryl L. Pierce <mcpierce@gmail.com>
Famous last words:
"I wonder what happens if we do it this way?"
If you're just trying to get notified on method calls rather than, say,
manipulating the arguments and re-calling, would something like Class: TracePoint (Ruby 2.1.1) work for you?
Ryan
···
On Thu, Mar 19, 2015 at 10:37 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
On Thu, Mar 19, 2015 at 11:03 AM, Darryl L. Pierce <mcpierce@gmail.com> wrote:
On Thu, Mar 19, 2015 at 10:39:13AM -0700, Ryan Mitchell wrote:
> If you're just trying to get notified on method calls rather than, say,
> manipulating the arguments and re-calling, would something like
> http://ruby-doc.org/core-2.1.1/TracePoint.html work for you?
Not method calls, but assignments and updates to instance variables on
an object; i.e., like how, in Python, __getattr__ is invoked whenever an
object's attributes are changed.
--
Darryl L. Pierce <mcpierce@gmail.com> http://mcpierce.blogspot.com/
Famous last words:
"I wonder what happens if we do it this way?"
Not method calls, but assignments and updates to instance variables on
an object; i.e., like how, in Python, __getattr__ is invoked whenever an
object's attributes are changed.
···
On Thu, Mar 19, 2015 at 10:39:13AM -0700, Ryan Mitchell wrote:
If you're just trying to get notified on method calls rather than, say,
manipulating the arguments and re-calling, would something like http://ruby-doc.org/core-2.1.1/TracePoint.html work for you?
--
Darryl L. Pierce <mcpierce@gmail.com>
Famous last words:
"I wonder what happens if we do it this way?"
Interesting suggestion. However, at least initially, it's not doing
that. I think what's going on is too far below what TracePoint can
handle. I used the following code but don't see the assignment call
being displayed:
===[start]===
module Wrapper
def self.included(base)
puts "Wrapper.included"
trace = TracePoint.new(:c_call) do |tp|
puts "tp: event=#{tp.event} inspect=#{tp.inspect}"
end
trace.enable
end
end
class TestClass
include Wrapper
attr_accessor :test1
attr_accessor :test2
def initialize
puts "Initializing test1" @test1 = "1"
puts "Initializing test2" @test2 = "2"
end
end
test = TestClass.new
puts "Assigning test 1"
test.test1 = "5"
puts "Assigning test 2"
test.test2 = "Darryl"
===[end]===
···
On Thu, Mar 19, 2015 at 11:20:28AM -0700, Ryan Mitchell wrote:
There are a lot of positive side-effects to using that pattern. First, you can instrument anything quite easily. Second, you can switch to lazy-initializing or caching w/o batting an eye. Refactorings and all sorts of things are enabled by it.
Direct cvar/ivar access is pretty much an antipattern in my book. I still use it here and there, but I try not to.
···
On Mar 20, 2015, at 07:06, Darryl L. Pierce <mcpierce@gmail.com> wrote:
Hrm, I hadn't quite thought of it like that; i.e., discouraging using @
instance variables in code that uses our library. I was hoping to make
the code work as unobtrusively as possible. But you make a great point
that, by encouraging this sort of pattern, it gives us more ability to
enhance the library over time.