From: redmine.ruby-lang.org@...
Date: 2015-02-05T19:39:02+00:00
Subject: [ruby-core:68028] [ruby-trunk - Feature #8564] Extend	Module#attr... methods

Issue #8564 has been updated by Tyler Rick.


I would love to see this added to Ruby too, so that I don't have to repeat myself by **defining** attributes in one place and then **initializing** them later in `initialize` (as discussed in #5825 and #8563).

In the meantime, however, I've come across the [fattr](https://github.com/ahoward/fattr) gem, which does exactly the same thing (plus a few extra things like defining a `foo!` method to *re-initialize*; I don't think `attr_reader` should do those extra things).  (By the way, there was a great [RubyTapas episode](http://www.rubytapas.com/episodes/276-Fattr) (subscription required) about fattr that got me excited about using it.)

Note that it's possible to support *both* initializing an attribute **to a Proc** *and* using a block to initialize a attribute **to an expression** that is evaluated during object initialization.

Here's how [fattr](https://github.com/ahoward/fattr) solves that problem...  If you pass a block to `fattr`, it is evaluated during initialization:

~~~ruby
class C
  fattr foo: 42
  fattr(:foo_2) { foo * 2 }  # evaluated during initialization
  fattr(:time) { Time.now }  # evaluated during initialization
end

p C.new.foo   #=> 42
p C.new.foo_2 #=> 84
p C.new.time  #=> 2015-02-05 ...
~~~

... whereas if you pass a block as the **value** for a hash key, it leaves it as a Proc and doesn't evaluate it:

~~~ruby
class C
  fattr my_proc: ->{ 'my_proc' }
end
p C.new.my_proc #=> #<Proc:0x0...>
p C.new.my_proc.() #=> 'my_proc'
~~~

I can't think of any downside to supporting the block behavior for `attr_accessor`. It doesn't appear that the block syntax of `attr_accessor` is used for anything currently...

~~~ruby
class C2
  attr_accessor(:foo_2) { foo * 2 }  # The block is never called
end

c = C2.new
p c.foo_2 #=> nil
~~~

Otherwise, you would be forced to add an `initialize` method any time you needed to initialize something to an expression that needed to be evaluated *at initialization time*, which would require duplication and mixing of initialization methods, which I think should be avoided:

~~~ruby
class C
  fattr foo: 42
  attr_accessor :foo_2
  def initialize
    @foo_2 = foo * 2
  end
end

p C.new.foo   #=> 42
p C.new.foo_2 #=> 84
~~~

----------------------------------------
Feature #8564: Extend Module#attr... methods
https://bugs.ruby-lang.org/issues/8564#change-51414

* Author: Boris Stitnicky
* Status: Open
* Priority: Normal
* Assignee: 
----------------------------------------
Extend #attr_reader, #attr_writer, #attr_accessor syntax to accept default values, such as:

    attr_reader foo: 42, bar: 43

Possibility of closures evaluated at initialization time might also be considered:

    attr_reader baz: -> { Time.now }, quux: 42

    



-- 
https://bugs.ruby-lang.org/