18710

[code]

    class Hoge
      attr_accessor :foo
    
      def initialize(value)
        @foo = Foo.new(value)
      end
    end
    
    class Foo
      attr_accessor :value
    
      def initialize(value)
        @value = value
      end
    end
    
    values = [
      Hoge.new(1),
      Hoge.new(2)
    ]
    
    
    p values.map{|hoge| hoge.foo.value} #=> 問題なし
    p values.map(&:foo.value) #=> エラー
    
[/code]

> undefined method `value' for :foo:Symbol (NoMethodError)

サンプルソースは上記のとおりです。  
エラーが起きているものの行の上の行と同等の動きをすると想定していますが、文法的に認識してくれずエラーのようです。正しい書き方はありますか？


CC BY-SA 3.0
2015-11-12T02:49:05.803
18709
2015-11-12T03:58:41.690
9008
question
ruby
mapに与える&を.（ドット）で繋ぎたい


結論から言うと不可能です。

まず文法上の認識の間違いがあります。  
`&:foo.value`の解釈は、  
&[:foo.value]となります。 よって :foo に .value が存在せずエラーとなります。  
検証方法として`values.map(&:FOO.downcase)`を実行してみてください。`:FOO.downcase #=>
:foo`ですから何のエラーも起こしません。

次に、`values.map(&:'foo')`が可能なので`values.map(&:'foo.value')`が可能であると思われるかもしれません。しかしこれも不可能です。  
なぜなら`values.map{|x| x.send(:'foo.value')}`と等しくなりますのでundefined method
`foo.value'が発生します。


CC BY-SA 3.0
2015-11-12T03:25:59.773
18710
2015-11-12T03:25:59.773
8335
18709
answer


Norikaz Ishiiさんも書いているとおり、普通にやろうとすると無理です。

そこでいくつか代替案を出してみます。

## 案1：素直に書く

無理せず、ブロックの中にコードを書けばいいじゃない、という案です。  
僕も普通こうします。

[code]

    values.map {|hoge| hoge.foo.value }
    
[/code]

## 案2：メソッドを定義する

自分でクラスを拡張できるなら、一発で値を取ってこれるメソッドを定義してみては？という案です。  
「デメテルの法則（[参考](http://qiita.com/hirokidaichi/items/d6c473d8011bd9330e63)）」にも違反しないので、オブジェクト指向的にはよいアプローチかもしれません。

[code]

    class Hoge
      attr_accessor :foo
    
      def initialize(value)
        @foo = Foo.new(value)
      end
    
      def foo_value
        foo.value
      end
    end
    
    values.map(&:foo_value)
    
[/code]

## 案3：gemを使う

[yuroyoro/lambda_driver](https://github.com/yuroyoro/lambda_driver)
というgemを使うと、質問で挙げられたコードに近いコードが書けます。

[code]

    require 'lambda_driver'
    
    values.map(&:foo >> :value)
    
[/code]

ご自身の好みに合うアプローチを採用してみてください。


CC BY-SA 3.0
2015-11-12T03:58:41.690
18712
2015-11-12T03:58:41.690
85
18709
answer