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.
John L. (Guest)
on 2006-05-04 04: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
unknown (Guest)
on 2006-05-04 07:01
(Received via mailing list)
On Thu, 4 May 2006, John L. 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
Kev J. (Guest)
on 2006-05-04 07: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
James B. (Guest)
on 2006-05-04 08:07
(Received via mailing list)
John L. 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 B.

"A principle or axiom is of no value without the rules for applying it."
   - Len Bullard
John L. (Guest)
on 2006-05-04 09:05
(Received via mailing list)
On 5/4/06, James B. <removed_email_address@domain.invalid> 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).
John L. (Guest)
on 2006-05-04 09: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
Logan C. (Guest)
on 2006-05-04 09:29
(Received via mailing list)
On May 4, 2006, at 1:07 AM, John L. 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
Logan C. (Guest)
on 2006-05-04 09:44
(Received via mailing list)
On May 4, 2006, at 1:28 AM, Logan C. 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.
Dave B. (Guest)
on 2006-05-04 09:48
(Received via mailing list)
John L. 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 C. 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
unknown (Guest)
on 2006-05-04 11:03
(Received via mailing list)
Hi --

On Thu, 4 May 2006, John L. 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
John L. (Guest)
on 2006-05-04 17: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
John L. (Guest)
on 2006-05-04 17:39
(Received via mailing list)
For more detail, see my reply to Dave B., but it's all about being
able to
generically marshal the 'attributes' of a type in RubyCLR.

Cheers,
-John
http://www.iunknown.com
Logan C. (Guest)
on 2006-05-04 17:39
(Received via mailing list)
On May 4, 2006, at 9:35 AM, John L. 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.