[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Inspecting a block given to a method

Thomas Mueller

3/4/2008 11:00:00 PM

Hi,

I am using JRuby to access data in some business application (Siebel,
if anybody is interested).
In Siebel I need to activate fields if I want to access them later:

bc.activate_field(name)
bc.query(search_specs)
do stuff

I've written methods that do the query and then yield each record to a
given block, so I can write something like:

bc.activate_field("field1")
bc.activate_field("field2")
bc.find_all(search_specs) do |record|
record["field1"] = "some value"
puts record["field2"]
end

I would like to do the activate_field() calls automatically, based on
which fields are being accessed inside the block.
Is it possible to look into the block and find out which fields are
being accessed? In the above example that would include the fields
"field1" and "field2".
Basically, can I access the code inside the block and inspect it?

Thomas

9 Answers

Christopher Dicely

3/5/2008 12:22:00 AM

0

On Tue, Mar 4, 2008 at 3:00 PM, Thomas Mueller
<thomasmueller76@googlemail.com> wrote:
> Hi,
>
> I am using JRuby to access data in some business application (Siebel,
> if anybody is interested).
> In Siebel I need to activate fields if I want to access them later:
>
> bc.activate_field(name)
> bc.query(search_specs)
> do stuff
>
> I've written methods that do the query and then yield each record to a
> given block, so I can write something like:
>
> bc.activate_field("field1")
> bc.activate_field("field2")
> bc.find_all(search_specs) do |record|
> record["field1"] = "some value"
> puts record["field2"]
> end
>
> I would like to do the activate_field() calls automatically, based on
> which fields are being accessed inside the block.
> Is it possible to look into the block and find out which fields are
> being accessed? In the above example that would include the fields
> "field1" and "field2".
> Basically, can I access the code inside the block and inspect it?


I don't know of any way to do that. But I don't think you need to:
you can yield a proxy object to the block that intercepts the
references (the []= methods on the record object, or anything else
that requires activation) and activates fields as necessary, before
passing the call on to the object that does the real work, I think.

Thomas Mueller

3/5/2008 12:56:00 AM

0

Thanks for your quick reply. If I understand you correctly that would
result in something like this being executed:

bc.find_all(search_specs) do |record|
activate("field1") # this is what the proxy object would do
record["field1"] = "some value"
activate("field2") # this is what the proxy object would do
puts record["field2"]
end

That wouldn't work because the fields need to be activated before I
query the data, basically before or at the beginning of the find_all()
method.

When I query for data in Siebel it issues SQL statements to the
database and only includes activated fields. Activating fields just
before accessing them doesn't work - they need to be activated before
querying the database.

My find_all() looks something like this:

def find_all
self.clear_to_query()
self.set_search_spec(...) # several of those, based on arguments to find_all()
self.execute_query()

begin
yield self
end while self.next_record() if self.first_record()
end

The fields need to be activated before the execute_query() call.

Thomas


2008/3/5, Christopher Dicely <cmdicely@gmail.com>:
> On Tue, Mar 4, 2008 at 3:00 PM, Thomas Mueller
> <thomasmueller76@googlemail.com> wrote:
> > Hi,
> >
> > I am using JRuby to access data in some business application (Siebel,
> > if anybody is interested).
> > In Siebel I need to activate fields if I want to access them later:
> >
> > bc.activate_field(name)
> > bc.query(search_specs)
> > do stuff
> >
> > I've written methods that do the query and then yield each record to a
> > given block, so I can write something like:
> >
> > bc.activate_field("field1")
> > bc.activate_field("field2")
> > bc.find_all(search_specs) do |record|
> > record["field1"] = "some value"
> > puts record["field2"]
> > end
> >
> > I would like to do the activate_field() calls automatically, based on
> > which fields are being accessed inside the block.
> > Is it possible to look into the block and find out which fields are
> > being accessed? In the above example that would include the fields
> > "field1" and "field2".
> > Basically, can I access the code inside the block and inspect it?
>
>
>
> I don't know of any way to do that. But I don't think you need to:
> you can yield a proxy object to the block that intercepts the
> references (the []= methods on the record object, or anything else
> that requires activation) and activates fields as necessary, before
> passing the call on to the object that does the real work, I think.
>
>

Christopher Dicely

3/5/2008 2:35:00 AM

0

On Tue, Mar 4, 2008 at 4:56 PM, Thomas Mueller
<thomasmueller76@googlemail.com> wrote:
> Thanks for your quick reply. If I understand you correctly that would
> result in something like this being executed:
>
>
> bc.find_all(search_specs) do |record|
> activate("field1") # this is what the proxy object would do
> record["field1"] = "some value"
> activate("field2") # this is what the proxy object would do
> puts record["field2"]
> end
>
> That wouldn't work because the fields need to be activated before I
> query the data, basically before or at the beginning of the find_all()
> method.
>
> When I query for data in Siebel it issues SQL statements to the
> database and only includes activated fields. Activating fields just
> before accessing them doesn't work - they need to be activated before
> querying the database.
>
> My find_all() looks something like this:
>
> def find_all
> self.clear_to_query()
> self.set_search_spec(...) # several of those, based on arguments to find_all()
> self.execute_query()
>
> begin
> yield self
> end while self.next_record() if self.first_record()
> end
>
> The fields need to be activated before the execute_query() call.

Hmm. That's trickier. You could create an method on some convenient class
(or object) from the block with define_method, and then use ParseTree to get
the parse tree of that method, and walk through the resulting s-expression to
find out which fields are called. Though if any of the fields are determined
dynamically, that won't work, because you won't have the results of the
dynamic determination, just the parse tree of the code that would get it.

(My ParseTree-fu isn't strong enough to sketch out code to demonstrate that,
but conceptually, with the caveat about dynamic determination of fields,
it seems at least possible.)

William James

3/5/2008 2:55:00 AM

0



Thomas Mueller wrote:
> Hi,
>
> I am using JRuby to access data in some business application (Siebel,
> if anybody is interested).
> In Siebel I need to activate fields if I want to access them later:
>
> bc.activate_field(name)
> bc.query(search_specs)
> do stuff
>
> I've written methods that do the query and then yield each record to a
> given block, so I can write something like:
>
> bc.activate_field("field1")
> bc.activate_field("field2")
> bc.find_all(search_specs) do |record|
> record["field1"] = "some value"
> puts record["field2"]
> end
>
> I would like to do the activate_field() calls automatically, based on
> which fields are being accessed inside the block.
> Is it possible to look into the block and find out which fields are
> being accessed? In the above example that would include the fields
> "field1" and "field2".
> Basically, can I access the code inside the block and inspect it?
>
> Thomas

bc.find_all(search_specs,'field1','field2') { |record,fields|
record[field[0]] = "some value"
puts record[field[1]]
}

William James

3/5/2008 2:57:00 AM

0

On Mar 4, 8:54 pm, William James <w_a_x_...@yahoo.com> wrote:
> Thomas Mueller wrote:
> > Hi,
>
> > I am using JRuby to access data in some business application (Siebel,
> > if anybody is interested).
> > In Siebel I need to activate fields if I want to access them later:
>
> > bc.activate_field(name)
> > bc.query(search_specs)
> > do stuff
>
> > I've written methods that do the query and then yield each record to a
> > given block, so I can write something like:
>
> > bc.activate_field("field1")
> > bc.activate_field("field2")
> > bc.find_all(search_specs) do |record|
> > record["field1"] = "some value"
> > puts record["field2"]
> > end
>
> > I would like to do the activate_field() calls automatically, based on
> > which fields are being accessed inside the block.
> > Is it possible to look into the block and find out which fields are
> > being accessed? In the above example that would include the fields
> > "field1" and "field2".
> > Basically, can I access the code inside the block and inspect it?
>
> > Thomas
>
> bc.find_all(search_specs,'field1','field2') { |record,fields|
> record[field[0]] = "some value"
> puts record[field[1]]}

A couple of s's were missing.

bc.find_all(search_specs,'field1','field2') { |record,fields|
record[fields[0]] = "some value"
puts record[fields[1]]}

Thomas Mueller

3/5/2008 3:33:00 AM

0

I think that'll be sufficient. My goal is to make it easy for the user
(which is mainly myself) to be lazy :-) and activate the fields
automatically. If I can't capture the usage of some fields sometimes
then those fields can still manually be activated.
I'm already installing ParseTree and will try that out. Looks promising.

Thanks a lot.


2008/3/5, Christopher Dicely <cmdicely@gmail.com>:
>
>
> Hmm. That's trickier. You could create an method on some convenient class
> (or object) from the block with define_method, and then use ParseTree to get
> the parse tree of that method, and walk through the resulting s-expression to
> find out which fields are called. Though if any of the fields are determined
> dynamically, that won't work, because you won't have the results of the
> dynamic determination, just the parse tree of the code that would get it.
>
> (My ParseTree-fu isn't strong enough to sketch out code to demonstrate that,
> but conceptually, with the caveat about dynamic determination of fields,
> it seems at least possible.)
>
>

Thomas Mueller

3/5/2008 3:34:00 AM

0

2008/3/5, William James <w_a_x_man@yahoo.com>:
> bc.find_all(search_specs,'field1','field2') { |record,fields|
>
> record[fields[0]] = "some value"
> puts record[fields[1]]}
>
>
That would work but the user would still have to identify the fields
that need to be activated. I'd rather have that done automatically.

Thanks anyways.

John Wilger

3/5/2008 5:41:00 AM

0

On Mar 4, 4:56 pm, Thomas Mueller <thomasmuelle...@googlemail.com>
wrote:
> Thanks for your quick reply. If I understand you correctly that would
> result in something like this being executed:
>
> bc.find_all(search_specs) do |record|
>   activate("field1")  # this is what the proxy object would do
>   record["field1"] = "some value"
>   activate("field2")  # this is what the proxy object would do
>   puts record["field2"]
> end
>
> That wouldn't work because the fields need to be activated before I
> query the data, basically before or at the beginning of the find_all()
> method.
<snip>
> My find_all() looks something like this:
>
> def find_all
>   self.clear_to_query()
>   self.set_search_spec(...) # several of those, based on arguments to find_all()
>   self.execute_query()
>
>   begin
>     yield self
>   end while self.next_record() if self.first_record()
> end

You could instead yield to the given block /before/ doing the actual
query and pass in an object which would simply record the method
calls. Then you could figure out the fields that need to be activated
from that, do the query, and replay the method calls on the actual
records returned. This would get difficult if you tried to do anything
beyond basic one-liners within the block, but it might work.

--
Regards,

John Wilger

Phlip

3/5/2008 6:04:00 AM

0

> bc.find_all(search_specs) do |record|
> activate("field1") # this is what the proxy object would do
> record["field1"] = "some value"
> activate("field2") # this is what the proxy object would do
> puts record["field2"]
> end

I'll take a stab at this one without (>cough<) reading the entire thread. We
need a DSL with two requirements - premature optimization, and a declarative
syntax. It might solve the OP's problem, or maybe someone else's problem.
Call it like this:

bc.find_all(search_specs) do |r|
foo = r.get("field1")
r.set("field2", "some value")
bar = r.get("field4") # this is what the proxy object would do
puts bar
end

I threw away the common syntactic sugar, like = for assignment. I think we
could get it back.

The DSL would work in several passes. The first time find_all calls its
block, it passes a write-only object for the 'r'. That object records
interest in field1, ~2, and ~4. And it sticks either 'nil' into 'foo' and
'bar', or it sticks some sentinel value which is impossible for databases to
stick in.

Then find_all sets up a database cursor that SELECTs only those three
fields. Then it plugs the cursor into a real, read-write object for 'r'.

This passes into the block once per record, and efficiently reads or writes
those fields.

The goal of this DSL is users of find_all can write many different search
specs, and can mix and match many different fields inside the block, without
worrying about the pernicious effects of certain database layers (such as
>cough< ActiveRecord) that tend to read everything in a database when the
wind blows.

> You could instead yield to the given block /before/ doing the actual query
> and pass in an object which would simply record the method calls. Then you
> could figure out the fields that need to be activated from that, do the
> query, and replay the method calls on the actual records returned. This
> would get difficult if you tried to do anything beyond basic one-liners
> within the block, but it might work.

Yeah, what he said.

Also, DSLs like ActiveRecord have shown us that a lot more syntactic sugar
is available, beyond my feeb get and set calls...

--
Phlip