I'm building a wrapper around a web service and I'd like to have my
class simply pass through calls to the remote service (since the
remote service will be adding new objects and methods faster then I'll
be updating the library, I need my class to be accept anything).
For example, if my ruby class is named API, I want to be able to call
API.images.find_by_name and have my class pass along "images" and
"find_by_name" to the remove service. I've got this working using two
method_missing calls (one as a class method and one as an instance
method), but it looks sloppy and I was wondering if there was a better
way to do this. Any ideas?
class API
def self.method_missing(remote_object)
api = API.new
api.instance_variable_set("@remote_object", remote_object)
return api
end
def method_missing(remote_method, *args)
API.call(@remote_object, remote_method, args)
end
def self.call(remote_object, remote_method, args)
puts "#{remote_object}.#{remote_method} #{args}"
end
end
Wouldn't the standard delegator library suffice? The description in the Pickaxe is more complete than the rdoc shown by ri.
-- fxn
···
El Aug 4, 2007, a las 1:50 AM, Dan escribió:
I'm building a wrapper around a web service and I'd like to have my
class simply pass through calls to the remote service (since the
remote service will be adding new objects and methods faster then I'll
be updating the library, I need my class to be accept anything).
The flickr library (available via RubyGems) walks around the problem
by turning a Flickr API call such as:
flickr.tags.getListUser
into a Ruby call like:
flickr.tags_getListUser
so that it can forward the method to Flickr through a single
method_missing.
It also provides a more granular object model around the call, so
there is still some duplication left:
class Flickr
class User
def tags
# @client is a Flickr object @client.tags_getListUser('user_id'=>@id)['who']['tags']
['tag'].collect { |tag| tag }
end
...
You might or might not like this, but it looks like a decent trade-off
to me. It's simple, and you can still make calls to the back-end that
are not directly supported by your Ruby code.
···
On Aug 4, 1:49 am, Dan <dan.gottl...@gmail.com> wrote:
For example, if my ruby class is named API, I want to be able to call
API.images.find_by_name and have my class pass along "images" and
"find_by_name" to the remove service. I've got this working using two
method_missing calls (one as a class method and one as an instance
method), but it looks sloppy and I was wondering if there was a better
way to do this. Any ideas?
---
Paolo Perrotta - Bologna, Italy
Now writing: "Metaprogramming Ruby"
Thanks for the reply. I'm probably being dense here, but I don't see
how Delegator would help in this scenario. Can you explain what you
mean?
Thanks!
Dan
···
On Aug 3, 8:02 pm, Xavier Noria <f...@hashref.com> wrote:
El Aug 4, 2007, a las 1:50 AM, Dan escribió:
> I'm building a wrapper around a web service and I'd like to have my
> class simply pass through calls to the remote service (since the
> remote service will be adding new objects and methods faster then I'll
> be updating the library, I need my class to be accept anything).
Wouldn't the standard delegator library suffice? The description in
the Pickaxe is more complete than the rdoc shown by ri.
You are dispatching everything to some object dynamically. That's what the delegator library is made for and that's why it rang a bell when you asked for alternatives to that implementation. It is just an idea for you to see whether it is worthwile compared to your approach.
According to the code there are two levels of catchall: The first one is a class-level catchall, it creates a new object out of something like API.images. The second one dispatches to that object somehow. Delegation would target the former so the class-level method_missing would return an object that already has delegation builtin.
Without seeing the real intented usage I can't be more specific. It could be that the way to call the remote service only uses symbols and there's no real object locally. If that was the case the delegator library wouldn't fit.
-- fxn
···
El Aug 4, 2007, a las 1:29 PM, Dan escribió:
Thanks for the reply. I'm probably being dense here, but I don't see
how Delegator would help in this scenario. Can you explain what you
mean?
Ok, I see where you were going now. I guess I could go in that
direction, but since sending functions and objects to the web service
is just done via POST params, so I'd rather route all the requests to
the "call" class method on my API class. Any ideas on how to do this
without having to create a instance of the API class (or any class)
just to store the "object" name ?
Dan
···
On Aug 4, 9:27 am, Xavier Noria <f...@hashref.com> wrote:
El Aug 4, 2007, a las 1:29 PM, Dan escribió:
> Thanks for the reply. I'm probably being dense here, but I don't see
> how Delegator would help in this scenario. Can you explain what you
> mean?
I guess the one being dense was me then :-).
You are dispatching everything to some object dynamically. That's
what the delegator library is made for and that's why it rang a bell
when you asked for alternatives to that implementation. It is just an
idea for you to see whether it is worthwile compared to your approach.
According to the code there are two levels of catchall: The first one
is a class-level catchall, it creates a new object out of something
like API.images. The second one dispatches to that object somehow.
Delegation would target the former so the class-level method_missing
would return an object that already has delegation builtin.
Without seeing the real intented usage I can't be more specific. It
could be that the way to call the remote service only uses symbols
and there's no real object locally. If that was the case the
delegator library wouldn't fit.
translates to a POST request where "images" and "find_by_name" are string values?
-- fxn
···
El Aug 4, 2007, a las 4:20 PM, Dan escribió:
Ok, I see where you were going now. I guess I could go in that
direction, but since sending functions and objects to the web service
is just done via POST params, so I'd rather route all the requests to
the "call" class method on my API class. Any ideas on how to do this
without having to create a instance of the API class (or any class)
just to store the "object" name ?
This is what I'd do (attached). Note, you need to know the number of
invocations in this example. The pattern could however use other
criteria for triggering the action.
Ok, I see where you were going now. I guess I could go in that
direction, but since sending functions and objects to the web service
is just done via POST params, so I'd rather route all the requests to
the "call" class method on my API class. Any ideas on how to do this
without having to create a instance of the API class (or any class)
just to store the "object" name ?
On Aug 4, 10:55 am, Xavier Noria <f...@hashref.com> wrote:
El Aug 4, 2007, a las 4:20 PM, Dan escribió:
> Ok, I see where you were going now. I guess I could go in that
> direction, but since sending functions and objects to the web service
> is just done via POST params, so I'd rather route all the requests to
> the "call" class method on my API class. Any ideas on how to do this
> without having to create a instance of the API class (or any class)
> just to store the "object" name ?
The idea is then that something like
API.images.find_by_name(name)
translates to a POST request where "images" and "find_by_name" are
string values?
Thanks for the reply. I was wondering if that there was a way to do
this sort of thing in ruby without having to create a class instance
just to store the method calls. However, it looks like that's not
possible, which I kind of understand. Not perfect for my situation,
but it should be good enough.
Dan
···
On Aug 6, 2:53 am, "Robert Klemme" <shortcut...@googlemail.com> wrote:
2007/8/4, Dan <dan.gottl...@gmail.com>:
> Ok, I see where you were going now. I guess I could go in that
> direction, but since sending functions and objects to the web service
> is just done via POST params, so I'd rather route all the requests to
> the "call" class method on my API class. Any ideas on how to do this
> without having to create a instance of the API class (or any class)
> just to store the "object" name ?
This is what I'd do (attached). Note, you need to know the number of
invocations in this example. The pattern could however use other
criteria for triggering the action.
Yeah, I would have written the same implementatcion than you to support that usage.
Perhaps API.images would return a different class instead of API itself with its own method missing depending on the role of that API.images conceptually, but that would be essentially the same approach anyway.
Looks fine to me.
-- fxn
···
El Aug 4, 2007, a las 5:05 PM, Dan escribió:
The idea is then that something like
API.images.find_by_name(name)
translates to a POST request where "images" and "find_by_name" are
string values?
Can you explain why you are reluctant to create an instance for this?
Generally, creating and manipulating objects is all OO is about.
More specifically, since your remote call is likely an order of
magnitude slower than the instance creation performance effects are
negligible.
Kind regards
robert
···
2007/8/7, Dan <dan.gottlieb@gmail.com>:
On Aug 6, 2:53 am, "Robert Klemme" <shortcut...@googlemail.com> wrote:
> 2007/8/4, Dan <dan.gottl...@gmail.com>:
>
> > Ok, I see where you were going now. I guess I could go in that
> > direction, but since sending functions and objects to the web service
> > is just done via POST params, so I'd rather route all the requests to
> > the "call" class method on my API class. Any ideas on how to do this
> > without having to create a instance of the API class (or any class)
> > just to store the "object" name ?
>
> This is what I'd do (attached). Note, you need to know the number of
> invocations in this example. The pattern could however use other
> criteria for triggering the action.
>
> Kind regards
>
> robert
>
> call-recorder.rb
> 1KDownload
Hi Robert,
Thanks for the reply. I was wondering if that there was a way to do
this sort of thing in ruby without having to create a class instance
just to store the method calls. However, it looks like that's not
possible, which I kind of understand. Not perfect for my situation,
but it should be good enough.
Thanks - I appreciate your working this through with me.
···
On Aug 5, 3:09 pm, Xavier Noria <f...@hashref.com> wrote:
El Aug 4, 2007, a las 5:05 PM, Dan escribió:
>> The idea is then that something like
>> API.images.find_by_name(name)
>> translates to a POST request where "images" and "find_by_name" are
>> string values?
> exactly
Yeah, I would have written the same implementatcion than you to
support that usage.
Perhaps API.images would return a different class instead of API
itself with its own method missing depending on the role of that
API.images conceptually, but that would be essentially the same
approach anyway.
Can you explain why you are reluctant to create an instance for this?
Generally, creating and manipulating objects is all OO is about.
More specifically, since your remote call is likely an order of
magnitude slower than the instance creation performance effects are
negligible.
Fair point :). Actually, I'm less concerned about performance then
code clarity. Since I'm just posting to a url, I only want to convert
the object-like notation to a string. Creating a bunch of objects just
to facilitate that notation seems like extra confusion.
We're not talking about a "bunch", are we? The reason I keep stressing this point is that more often than not I have seen OO programs make too few use of classes than making too much use of classes. Somehow people seem to think a class is something big or heavyweight so it should be avoided - or at least kept to a minimum. IMHO that leads to less modularized and more difficult to read code. Stuffing everything into only few classes that have a large number of methods makes things harder to understand and reuse than having many classes which focus on only few related tasks and that use other classes for unrelated tasks.
Sorry, I *had* to say it at some point in time.
Kind regards
robert
···
On 07.08.2007 16:09, Dan wrote:
Can you explain why you are reluctant to create an instance for this?
Generally, creating and manipulating objects is all OO is about.
More specifically, since your remote call is likely an order of
magnitude slower than the instance creation performance effects are
negligible.
Fair point :). Actually, I'm less concerned about performance then
code clarity. Since I'm just posting to a url, I only want to convert
the object-like notation to a string. Creating a bunch of objects just
to facilitate that notation seems like extra confusion.