Modifying Struct members

Discussion in 'Ruby' started by Yossef Mendelssohn, Jul 31, 2009.

  1. Is it possible to modify the members of a Struct class once it's been
    created, yet retain all other behavior?

    An example:

    Thing = Struct.new:)a, :b, :c) do
    def some_method
    end
    end

    Is there a way to modify Thing so it behaves as if it were effectively
    created like so?

    Thing = Struct.new:)a, :b, :c, :d) do
    def some_method
    end
    end

    Re-assigning Thing to a new Struct obviously doesn't work because then
    the behavior is lost.
    Altering Thing.members seemed promising, but that didn't work either.
    Adding attr_accessor for :d isn't good because I need Thing.new['d']
    to work.

    Thoughts?

    --
    -yossef
     
    Yossef Mendelssohn, Jul 31, 2009
    #1
    1. Advertising

  2. Yossef Mendelssohn wrote:
    > Is it possible to modify the members of a Struct class once it's been
    > created, yet retain all other behavior?
    >
    > An example:
    >
    > Thing = Struct.new:)a, :b, :c) do
    > def some_method
    > end
    > end
    >
    > Is there a way to modify Thing so it behaves as if it were effectively
    > created like so?
    >
    > Thing = Struct.new:)a, :b, :c, :d) do
    > def some_method
    > end
    > end
    >
    > Re-assigning Thing to a new Struct obviously doesn't work because then
    > the behavior is lost.
    > Altering Thing.members seemed promising, but that didn't work either.
    > Adding attr_accessor for :d isn't good because I need Thing.new['d']
    > to work.
    >
    > Thoughts?
    >
    > --
    > -yossef
    >
    >


    OpenStruct might be what you want:
    http://ruby-doc.org/core/classes/OpenStruct.html

    -Justin
     
    Justin Collins, Jul 31, 2009
    #2
    1. Advertising

  3. On Jul 31, 12:42=A0pm, Justin Collins <> wrote:
    > OpenStruct might be what you want:http://ruby-doc.org/core/classes/OpenSt=

    ruct.html

    I appreciate the thought, but it kind of doesn't matter what I might
    want. I have to stick with the crap I'm building on because I don't
    feel like rewriting a gem.

    In case anyone is wondering, the 'solution' (as in it works but I
    don't recommend it) with help from Aaron "tenderlove" Patterson, goes
    something like this.

    Thing =3D Struct.new:)a, :b, :c) do
    def some_thing
    end
    end

    class Thing
    attr_accessor :d

    alias_method :eek:ld_brackets, :[]
    def [](m)
    if m.to_s =3D=3D 'd'
    self.d
    else
    old_brackets(m)
    end
    end

    alias_method :eek:ld_brackets_equal, :[]=3D
    def []=3D(m, v)
    if m.to_s =3D=3D 'd'
    self.d =3D v
    else
    old_brackets_equal(m, v)
    end
    end
    end

    Tell me that doesn't make you unhappy.

    --
    -yossef
     
    Yossef Mendelssohn, Jul 31, 2009
    #3
  4. Yossef Mendelssohn

    Eric Hodel Guest

    On Jul 31, 2009, at 11:15, Yossef Mendelssohn wrote:
    > On Jul 31, 12:42 pm, Justin Collins <> wrote:
    >> OpenStruct might be what you want:http://ruby-doc.org/core/classes/OpenStruct.html

    >
    > I appreciate the thought, but it kind of doesn't matter what I might
    > want. I have to stick with the crap I'm building on because I don't
    > feel like rewriting a gem.


    What gem? You can't submit a patch? Contact the author?
     
    Eric Hodel, Jul 31, 2009
    #4
  5. Yossef Mendelssohn

    Ryan Davis Guest

    On Jul 31, 2009, at 09:50 , Yossef Mendelssohn wrote:

    > Is it possible to modify the members of a Struct class once it's been
    > created, yet retain all other behavior?
    >
    > An example:
    >
    > Thing = Struct.new:)a, :b, :c) do
    > def some_method
    > end
    > end
    >
    > Is there a way to modify Thing so it behaves as if it were effectively
    > created like so?
    >
    > Thing = Struct.new:)a, :b, :c, :d) do
    > def some_method
    > end
    > end


    I know this makes me a really bad person for doing this... but hey...
    that's what I'm here for. To take one for the team. I'm thinking of
    releasing 2 gems off of this idea. One for thaw and the other for
    struct... Hrm... there is still a problem with structs made before the
    additional member is added. I'll work that out, but I have to go to my
    workout now.

    #!/usr/bin/ruby -w

    require 'rubygems'
    require 'inline'

    class Object
    inline :C do |builder|
    builder.c "VALUE thaw() { FL_UNSET(self, FL_FREEZE); return
    self; }"
    end
    end

    class Struct
    inline :C do |builder|
    builder.c_singleton "
    void raw_members() {
    return rb_struct_s_members(self);
    }
    "

    builder.c_singleton '
    void set_size(long n) {
    rb_iv_set(self, "__size__", LONG2NUM(n));
    }
    ', :method_name => :size=
    end

    def self.add_member name
    self.raw_members.thaw
    self.raw_members << name

    attr_accessor name

    self.size = self.raw_members.size
    end
    end

    Thing = Struct.new:)a, :b, :c) do
    def some_thing
    end
    end

    t = Thing.new(1, 2, 3)

    p [t.a, t.b, t.c]
    # => [1, 2, 3]

    Thing.add_member :d

    t.d = 4

    p [t.a, t.b, t.c, t.d]
    # => [1, 2, 3, 4]
     
    Ryan Davis, Jul 31, 2009
    #5
  6. On Jul 31, 1:57=A0pm, Eric Hodel <> wrote:
    > What gem? =A0You can't submit a patch? =A0Contact the author?


    It's the freshbooks gem, and I haven't had luck with the author.

    Or, conversely, I haven't had the patience to get the gem/author up to
    snuff, and gave up about a year ago.

    --
    -yossef
     
    Yossef Mendelssohn, Jul 31, 2009
    #6
  7. Yossef Mendelssohn

    Ryan Davis Guest

    here we go:

    #!/usr/bin/ruby -w

    require 'rubygems'
    require 'inline'

    class Object
    inline :C do |builder|
    builder.c "VALUE thaw() { FL_UNSET(self, FL_FREEZE); return
    self; }"
    end
    end

    class Struct
    inline :C do |builder|
    builder.c_singleton "
    void raw_members() {
    return rb_struct_s_members(self);
    }
    "

    builder.c_singleton '
    void set_s_size(long n) {
    rb_iv_set(self, "__size__", LONG2NUM(n));
    }
    ', :method_name => :size=

    builder.c '
    void set_size(long n) {
    RSTRUCT(self)->len = n;
    }
    ', :method_name => :size=
    end

    def self.add_member name
    self.raw_members.thaw
    self.raw_members << name

    # a bit hacky, but works
    self.send:)define_method, name) { self[name] }
    self.send:)define_method, "#{name}=") { |o| self[name] = o }

    new_size = self.raw_members.size
    self.size = new_size

    ObjectSpace.each_object(self) do |o|
    o.size = new_size
    end
    end
    end

    Thing = Struct.new:)a, :b, :c) do
    def some_thing
    end
    end

    t = Thing.new(1, 2, 3)

    p [t.a, t.b, t.c]
    # => [1, 2, 3]

    Thing.add_member :d

    t.d = 4 # t['d'] = 4 works just as well now

    p(('a'..'d').map { |c| t[c] })
    # => [1, 2, 3, 4]
    p(('a'..'d').map { |c| t.send c })
    # => [1, 2, 3, 4]
     
    Ryan Davis, Jul 31, 2009
    #7
  8. Yossef Mendelssohn

    Eric Hodel Guest

    On Jul 31, 2009, at 17:27, MenTaLguY wrote:

    > ...am I missing something, or don't you also need to reallocate the
    > array?


    That part is done in ruby code using Array#<<
     
    Eric Hodel, Aug 1, 2009
    #8
  9. On Friday 31 July 2009 02:15:49 pm Yossef Mendelssohn wrote:

    > In case anyone is wondering, the 'solution' (as in it works but I
    > don't recommend it) with help from Aaron "tenderlove" Patterson, goes
    > something like this.

    [snip]
    > Tell me that doesn't make you unhappy.


    It doesn't. The fact that you can monkeypatch at all makes me very happy to be
    using Ruby.
     
    David Masover, Aug 1, 2009
    #9
    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. Brahmam
    Replies:
    3
    Views:
    576
    Francois Beaussier
    Jan 11, 2006
  2. JFCM
    Replies:
    4
    Views:
    5,779
  3. Chris Fogelklou
    Replies:
    36
    Views:
    1,438
    Chris Fogelklou
    Apr 20, 2004
  4. Replies:
    14
    Views:
    646
    RichardETVS
    May 29, 2007
  5. John Reye
    Replies:
    28
    Views:
    1,412
    Tim Rentsch
    May 8, 2012
Loading...

Share This Page