Syntax sugar: method[](...) => method(...)

Discussion in 'Ruby' started by Erwin Abbott, Jun 29, 2007.

  1. Erwin Abbott

    Erwin Abbott Guest

    Hi,

    The [] method is really handy when you have an object that should
    behave like a hash or array. One thing I find myself wishing I could
    also do is something like

    def logins[](date)
    @events.select{|e| e.action == :login and e.date == date}
    end

    There may be a better way to deal with this example, but this is just
    to demonstrate the circumstances where you don't have an array or hash
    called logins, but you'd like to be able to use that [] syntax. One
    way I though about doing it is

    def logins
    EventList.new @events.select{|e| e.action == :login}
    end

    class EventList
    def initialize data
    @data = data
    end
    def [] date
    @data.select{|e| e.date == date}
    end
    end

    logins[Date.today] # => all logins today from @events

    I guess some people might prefer to write a method like
    get_logins(date), but I like this syntax. It seems reasonable to also
    define []= in EventList to update the original @events. What I'd like
    to know is if there's another way to solve this problem, or if there
    are any simple optimizations (maybe only keep one instance of
    EventList and update its contents with each call to #events).

    Lastly, has there been any mention of allowing function names like so
    in ruby 1.9:
    def logins[] date
    # ...
    end

    Thanks,
    - Erwin
     
    Erwin Abbott, Jun 29, 2007
    #1
    1. Advertising

  2. Erwin Abbott

    Trans Guest

    On Jun 29, 4:17 pm, "Erwin Abbott" <> wrote:
    > Hi,
    >
    > The [] method is really handy when you have an object that should
    > behave like a hash or array. One thing I find myself wishing I could
    > also do is something like
    >
    > def logins[](date)
    > @events.select{|e| e.action == :login and e.date == date}
    > end
    >
    > There may be a better way to deal with this example, but this is just
    > to demonstrate the circumstances where you don't have an array or hash
    > called logins, but you'd like to be able to use that [] syntax. One
    > way I though about doing it is
    >
    > def logins
    > EventList.new @events.select{|e| e.action == :login}
    > end
    >
    > class EventList
    > def initialize data
    > @data = data
    > end
    > def [] date
    > @data.select{|e| e.date == date}
    > end
    > end
    >
    > logins[Date.today] # => all logins today from @events
    >
    > I guess some people might prefer to write a method like
    > get_logins(date), but I like this syntax. It seems reasonable to also
    > define []= in EventList to update the original @events. What I'd like
    > to know is if there's another way to solve this problem, or if there
    > are any simple optimizations (maybe only keep one instance of
    > EventList and update its contents with each call to #events).


    def logins
    @_logins ||= Proc.new do |date|
    @events.select{|e| e.action == :login and e.date == date}
    end
    end

    However, I feel you are limiting yourself. Try something like this
    instead:

    def logins
    @_logins ||= (
    l = @events.select{|e| e.action == :login}
    def l.by_date(date)
    select{|e| e.date == date}
    end
    l
    )
    end

    Then you can use:

    logins.by_date(date)

    If needed, you could change #logins to lazy evaluate too.

    T.
     
    Trans, Jun 30, 2007
    #2
    1. Advertising

  3. On 29.06.2007 22:17, Erwin Abbott wrote:
    > Hi,
    >
    > The [] method is really handy when you have an object that should
    > behave like a hash or array. One thing I find myself wishing I could
    > also do is something like
    >
    > def logins[](date)
    > @events.select{|e| e.action == :login and e.date == date}
    > end
    >
    > There may be a better way to deal with this example, but this is just
    > to demonstrate the circumstances where you don't have an array or hash
    > called logins, but you'd like to be able to use that [] syntax. One
    > way I though about doing it is
    >
    > def logins
    > EventList.new @events.select{|e| e.action == :login}
    > end
    >
    > class EventList
    > def initialize data
    > @data = data
    > end
    > def [] date
    > @data.select{|e| e.date == date}
    > end
    > end
    >
    > logins[Date.today] # => all logins today from @events
    >
    > I guess some people might prefer to write a method like
    > get_logins(date), but I like this syntax. It seems reasonable to also
    > define []= in EventList to update the original @events. What I'd like
    > to know is if there's another way to solve this problem, or if there
    > are any simple optimizations (maybe only keep one instance of
    > EventList and update its contents with each call to #events).


    It's pretty easy to achieve what you want:

    irb(main):001:0> class Foo
    irb(main):002:1> def logins
    irb(main):003:2> x = %w{a b c}
    irb(main):004:2> def x.[](a)
    irb(main):005:3> select {|e| e == a}
    irb(main):006:3> end
    irb(main):007:2> x
    irb(main):008:2> end
    irb(main):009:1> end
    => nil
    irb(main):010:0> f=Foo.new
    => #<Foo:0x7ff7abc8>
    irb(main):014:0> f.logins["w"]
    => []
    irb(main):015:0> f.logins["a"]
    => ["a"]

    Here's another variant:

    irb(main):016:0> class Bar
    irb(main):017:1> def logins
    irb(main):018:2> x = %w{a b c}
    irb(main):019:2> lambda {|a| x.select {|e| e == a}}
    irb(main):020:2> end
    irb(main):021:1> end
    => nil
    irb(main):022:0> b=Bar.new
    => #<Bar:0x7ff5bfe8>
    irb(main):023:0> b.logins["a"]
    => ["a"]
    irb(main):024:0> b.logins["w"]
    => []

    I.e. you just create a proxy object that will handle the [] call.
    However I am not sure it's a good idea - it's probably better to return
    the original array or a copy of it.

    Kind regards

    robert
     
    Robert Klemme, Jul 9, 2007
    #3
  4. Erwin Abbott

    Erwin Abbott Guest

    Hi Logan,

    Really cool stuff going on there, that was worth a thousand words. I
    never knew about this UnboundMethod#bind thing, curious if Proc has a
    similar mechanism. Also happy to learn Method#[] is an alias to
    Method#call

    Let me summarize what's going on here to make sure I understand. First
    we're creating an UnboundMethod from the given block. Next we create
    the named method, which returns a blank object with a [] method that
    calls the block. Okay, that was simpler than I thought!

    One thing I'll be trying to work out is calling the method "logins"
    will return a plain Object instead of a list of @events that are of
    the type :login. I think for my purposes defining a few more singleton
    methods like obj.each and obj.size would be good enough.

    On 7/9/07, Logan Capaldo <> wrote:
    > class Module
    > def bracket(name, &code)
    > define_method("#{name}_bracketed", &code)
    > m = instance_method("#{name}_bracketed")
    > remove_method "#{name}_bracketed"
    >
    > define_method(name) do ||
    > obj = Object.new
    > m1 = m.bind(self)
    > (class << obj; self; end).module_eval { define_method:)[]) { |x|
    > m1[x] } }
    > obj
    > end
    > end
    > end
    >
    >
    > class Foo
    > bracket :logins do |date|
    > @data.select { |e| e.date == date }
    > end
    > end
    >
    > Who needs sugar?
    >
    > (I so didn't test this at all)


    Thanks,
    - Erwin
     
    Erwin Abbott, Jul 10, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jason Heyes

    Is -> syntactic sugar?

    Jason Heyes, Dec 15, 2003, in forum: C++
    Replies:
    17
    Views:
    588
    Ron Natalie
    Dec 19, 2003
  2. Bengt Richter
    Replies:
    37
    Views:
    747
    Anthony Baxter
    Aug 13, 2004
  3. Replies:
    0
    Views:
    95
  4. Eric Mahurin
    Replies:
    8
    Views:
    143
  5. aalfred

    Strange syntax sugar

    aalfred, Apr 24, 2007, in forum: Ruby
    Replies:
    5
    Views:
    142
    Nobuyoshi Nakada
    Apr 26, 2007
Loading...

Share This Page