Forum: Ruby Ruby idiom for attributes / properties

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2006-05-04 02:43
(Received via mailing list)
I'm writing a bunch of auto-marshaling code to let CLR code call back
into
Ruby. I just got the simplest possible marshaling scenario working
today,
which is letting you bind an Array of ActiveRecord objects to a CLR
DataGridView control. See
http://www.iunknown.com/articles/2006/05/03/active...
a longer discussion and a screenshot.

Bottom line is that I can now write:

data_grid.data_source = Person.find_by_last_name('Lam')

Now, here's my problem: I'm not all that happy that I'm special casing
my
code for ActiveRecord objects. However, since Ruby doesn't have a
mechanism
for runtime-discovery of attributes, I'm special casing for ActiveRecord
since it provides an @attributes hashtable with the name-value pairs for
all
attributes in the object. This makes it easy for me to generate the CLR
anonymous class + object that implements the marshaling code that
retrieves
the attribute data from the Ruby ActiveRecord object (think about this
as
marshal by reference).

Do folks have suggestions for implementing a discoverable attribute /
property idiom in Ruby? Perhaps via a mixin module in the standard
library?
Or has this been done already and I'm just showing my Ruby newbiness?

Thanks
-John
http://www.iunknown.com
Cb48ca5059faf7409a5ab3745a964696?d=identicon&s=25 unknown (Guest)
on 2006-05-04 05:01
(Received via mailing list)
On Thu, 4 May 2006, John Lam wrote:

>
> property idiom in Ruby? Perhaps via a mixin module in the standard library?
> Or has this been done already and I'm just showing my Ruby newbiness?
>
> Thanks
> -John
> http://www.iunknown.com

   harp:~ > cat a.rb
   require 'traits'

   class C
     trait 'a'
     traits 'b' => 42, 'c' => 42.0
     class_trait 'a'
   end

   p C.class_traits
   p C.traits


   harp:~ > ruby a.rb
   [["a", "a="]]
   [["a", "a="], ["b", "b="], ["c", "c="]]


and a whole lot more

   http://rubyforge.org/projects/codeforpeople/
   http://codeforpeople.com/lib/ruby/traits/traits-0.8.0/README

regards.

-a
2a0f7bd2c54fbc44329d69555b96f1c5?d=identicon&s=25 Kev Jackson (Guest)
on 2006-05-04 05:16
(Received via mailing list)
The example screenshot and the amount of code is very very cool. So far
I've not been forced to use .net, but RubyCLR gives me a chance of al
teas not having to mess with VB or C#.

Thanks for your work on this, it's amazing the progress that you're
making
Kev
Bc6d88907ce09158581fbb9b469a35a3?d=identicon&s=25 James Britt (Guest)
on 2006-05-04 06:07
(Received via mailing list)
John Lam wrote:
...

>
> Do folks have suggestions for implementing a discoverable attribute /
> property idiom in Ruby? Perhaps via a mixin module in the standard library?
> Or has this been done already and I'm just showing my Ruby newbiness?


What would you consider to be an attribute?



--
James Britt

"A principle or axiom is of no value without the rules for applying it."
   - Len Bullard
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2006-05-04 07:05
(Received via mailing list)
On 5/4/06, James Britt <james_b@neurogami.com> wrote:
>
> What would you consider to be an attribute?


I'm just borrowing the ActiveRecord terminology for attributes. In my
mind,
an attribute == a property. In .NET, a property is a bit of syntactical
sugar (but also a distinct metadata entity) for a getter and setter
method.

Consider this bit of C# code:

class Foo {
  public string StringProperty {
    get { return "string"; }
    set { Console.WriteLine("setting a string to " + value); }
  }
}

This generates under the covers a get_StringProperty and a
set_StringProperty method.

I would consider it equivalent to this Ruby code:

class Foo
  def string_property
     'string'
  end
  def string_property=(value)
    puts "setting a string to #{value}"
  end
end

The problem is that I can't distinguish a string_property method from
any
other method. In .NET, I can walk the property metadata to discover all
of
those properties (and those are things that can be bound to data-aware
controls in the framework).
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2006-05-04 07:08
(Received via mailing list)
Excellent!

Now the bigger question is - any chance this could become part of the
standard distribution? I could add another special case in my bridge to
marshal traits auto-magically as well, but it would rock if this
mechanism
could be something that I could grab a hold of when reflecting against
Ruby
objects at the marshaling boundary.

-John
http://www.iunknown.com
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 07:29
(Received via mailing list)
On May 4, 2006, at 1:07 AM, John Lam wrote:

>
> -John
> http://www.iunknown.com

You could do

class Module
  alias old_attr_reader attr_reader
  alias old_attr_writer attr_writer
  alias old_attr_accessor attr_accessor

  def attr_reader(*args)
      self.attributes |= args
      old_attr_reader(*args)
  end

  def attr_writer(*args)
      self.attributes |= args
      old_attr_writer(*args)
  end

  def attr_accessor(*args)
      self.attributes |= args
      old_attr_accessor(*args)
  end

  def attributes
      @attribs ||= []
  end

  def attributes=(new_attribs)
      @attribs = new_attribs
  end
end

class A
   attr_accessor :a
end

p A.attributes

Note that you'd have to make sure this was required before anything
else, and it only works for attributes declared with the attr_*
family of methods
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 07:44
(Received via mailing list)
On May 4, 2006, at 1:28 AM, Logan Capaldo wrote:

>
> Note that you'd have to make sure this was required before anything
> else, and it only works for attributes declared with the attr_*
> family of methods

Sorry to be replying to myself, but my code craps out with
inheritance and stuff. You'd have to do this meta-programming in a
much smarter way.
0b561a629b87f0bbf71b45ee5a48febb?d=identicon&s=25 Dave Burt (Guest)
on 2006-05-04 07:48
(Received via mailing list)
John Lam wrote:
>
> other method. In .NET, I can walk the property metadata to discover all of
> those properties (and those are things that can be bound to data-aware
> controls in the framework).

RDoc considers anything declared with the attr_* class methods an
"attribute", so that your string_property above isn't, but this is:

class Foo
  attr_accessor :string_property
end

One approach might be to hack attr_* to generate your metadata (as I see
Logan Capaldo has now suggested).

Another approach might be to simply narrow down what valid "attribute"
methods look like. Does it have to have a foo=() and foo() pair? Does
foo() have to be parameterless, or is it accept optional parameters
(like Ara's traits)? Then you can just pull those methods out of the
class:

class Module
  def attributes
    instance_methods.select do |name|
      next if name =~ /!$/ || name =~ /=$/
      setter = name.sub(/\?$/, "") + "="
      instance_methods.include?(setter) &&
        [0, -1].include?(instance_method(name).arity) &&
        [1, -2].include?(instance_method(setter).arity)
    end
  end
end

struct = Struct.new(:foo, :bar)
[Dir, File, IO, Hash, Thread, Struct::Tms, struct].each do |c|
  p [c, c.attributes]
end

=> [Dir, ["pos"]]
[File, ["sync", "lineno", "pos"]]
[IO, ["sync", "lineno", "pos"]]
[Hash, ["default"]]
[Thread, ["abort_on_exception", "priority"]]
[Struct::Tms, ["cutime", "cstime", "stime", "utime"]]
[#<Class:0x2c32660>, ["bar", "foo"]]

Cheers,
Dave
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2006-05-04 09:03
(Received via mailing list)
Hi --

On Thu, 4 May 2006, John Lam wrote:

>
> I would consider it equivalent to this Ruby code:
> The problem is that I can't distinguish a string_property method from any
> other method.

Why is that a problem? :-)  It does demonstrate, though, that the C#
and Ruby samples are not equivalent.

> In .NET, I can walk the property metadata to discover all of
> those properties (and those are things that can be bound to data-aware
> controls in the framework).

In general, the equivalent of a method name with the general format
get_x_property in Ruby is x, and the equivalent of set_x_property in
Ruby is x=.  There's room for debate as to whether there's really such
a thing as an "attribute" at the language level at all in Ruby; I tend
to think not, or very nearly not, since the only support for the
concept, other than the method mechanisms that are in the language
anyway, are the attr_* methods, and to my eyes those are just
convenience methods layered on top of the language.  (Then again, they
are in the language; hence the debate :-)


David
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2006-05-04 15:36
(Received via mailing list)
Hi Dave,

Duck typing for attributes - cool idea, but I worry about it because of
the
difficulty (impossibility) in telling read-only properties from ordinary
methods:

module Utilities
  def format_disk
  end
end

class Person
  include Utilities
  def first_name
  end
end

You see my interest in this topic is driven entirely around my ability
to
add some runtime magic in my marshaler. Since the metadata doesn't exist
in
Ruby, I have to rely on some kind of convention. I might need to add
that
convention via a mixin that you can write that serves as an adapter
between
the type that you want to make data-bindable in .NET. So you could patch
ActiveRecord in a RubyCLR app via:

class ActiveRecord
  include RubyClr::MakeBindable
end

This removes the hard-coded depenency on ActiveRecord from my marshaler.

Does this sound reasonable?

Thanks
-John
http://www.iunknown.com
2c8df79b2a68a7532af01d8851f7fa2d?d=identicon&s=25 John Lam (Guest)
on 2006-05-04 15:39
(Received via mailing list)
For more detail, see my reply to Dave Burt, but it's all about being
able to
generically marshal the 'attributes' of a type in RubyCLR.

Cheers,
-John
http://www.iunknown.com
E34b5cae57e0dd170114dba444e37852?d=identicon&s=25 Logan Capaldo (Guest)
on 2006-05-04 15:39
(Received via mailing list)
On May 4, 2006, at 9:35 AM, John Lam wrote:

>  end
> add some runtime magic in my marshaler. Since the metadata doesn't
>  include RubyClr::MakeBindable
>
I personally would much rather have RubyClr::MakeBindable then have
it try to 'guess'.
This topic is locked and can not be replied to.